I’ve been learning about the new features that each new Python release brings that are helpful to developers. Today we’ll start with Python 3.9, which is very middle-of-the-road and doesn’t have many valuable changes.
Add union operators to dict
In PEP 584 - Add Union Operators To dict it is proposed to add 2 operators to dict, |
and |=
.
There are two common ways to merge 2 dictionaries in the past:
1
2
3
4
5
6
7
8
9
10
|
In : a = {'a': 1}
In : b = {'b': 1}
In : {**a, **b} # Option 1, using **, Python 3.5 and above
Out: {'a': 1, 'b': 1}
In : c = a.copy() # Option 2, using update
In : c.update(b) # If you use a.update directly, it will modify the result of a directly
|
Of course, there are some more tricky ones, notably dict(list(x.items()) + list(y.items())
in Python 2, but I won’t mention them.
Python 3.9 onwards can be implemented using the or
operator.
1
2
3
4
5
6
|
In : a = {'a': 1}
In : b = {'b': 1}
In : a | b
Out: {'a': 1, 'b': 1}
|
If you want to replace directly after merging, you can use the update (|=
) operator.
1
2
3
4
5
6
7
|
In : a
Out: {'a': 1}
In : a |= b # Equivalent to a.update(b)
In : a
Out: {'a': 1, 'b': 1} # Direct replacement on a (in place)
|
Added string methods to remove prefixes and suffixes
New removeprefix
and removesuffix
methods have been added to PEP 616. In the past, you had to implement them yourself.
1
2
3
4
5
6
7
8
9
10
11
|
def removeprefix(self: str, prefix: str, /) -> str:
if self.startswith(prefix):
return self[len(prefix):]
else:
return self[:]
def removesuffix(self: str, suffix: str, /) -> str:
if suffix and self.endswith(suffix):
return self[:-len(suffix)]
else:
return self[:]
|
Of course, the corresponding methods for bytes
, bytearray
and collections.UserString
have been added as well.
My understanding of this feature is that it can be used to make some improvements to the code in CPython.
Decorator syntax improvements
In previous versions, a decorator is an object that needs to be determined, it does not support some scenarios where expressions are computed, and it does not support anonymous functions as decorators, for 2 examples.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
In : from dataclasses import dataclass
...: d = [dataclass]
...:
...: @d[0]
...: class A:
...: attr: int
...:
...: print(A)
...:
File "<ipython-input-1-cf77b251b3d6>", line 4
@d[0]
^
SyntaxError: invalid syntax
In : @lambda func: lambda *args: func(*args)+1
...: def plus(a, b):
...: return a + b
File "<ipython-input-3-236754e0ed07>", line 1
@lambda func: lambda *args: func(*args)+1
^
SyntaxError: invalid syntax
|
This will throw a syntax error straight away, and they all work fine now.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
In : from dataclasses import dataclass
...: d = [dataclass]
...:
...: @d[0]
...: class A:
...: attr: int
...:
In : print(A)
<class '__main__.A'>
In : @lambda func: lambda *args: func(*args)+1
...: def plus(a, b):
...: return a + b
...:
In : plus(1, 2)
Out: 4
|
Summary
There are really no new features that I’m excited about in this release.