What is new in Python 3.8

Python 3.8 is going to be released in October 2019 but you can taste it now. Currently the latest available version is python 3.8b2 (which is feature freezed). So what's new in Python 3.8?

f-string =

In python 3.8 you can output debug information more eloquently using f-string feature which was introduced in python 3.7. You just need to add = to it:

>> a = 123
>> b = 456
>> print(f'{a=} and {b=}')
a=123 and b=456

Assignment Expressions aka walrus operator :=

PEP572 is legendary because Guido decided to step down as BDFL after it was accepted. The idea behind := operator is to make code more readable and less nested. For example you want to check if a key is present in a dictionary and assign its value to a variable. Typically you will do the following:

params = {'foo': 'bar'}
x = params.get('foo')
if x:
    print(x)

But in Python 3.8 it can be expressed as:

params = {'foo': 'bar'}
if x := params.get('foo'):
    print(x)

Positional-only arguments

Keyword-only arguments (PEP3102) were introduced in Python 3 back in 2006. The idea behind this PEP is to restrict passing some arguments to functions or methods as positional. Let's see how it looks:

def test(a, b, *, key1, key2):
    pass
test(1,2,3,4)
Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    test(1,2,3,4)
TypeError: test() takes 2 positional arguments but 4 were given</module></pyshell#7>

Python interpreter warns that the last 2 arguments should be passed as keyword-arguments. The right way to invoke the function is:

test(1, 2, key1=3, key2=4)

Okay, but how to impose a restriction for positional-only arguments? Hooray! Now Python 3.8 let's you do this using / symbol:

def position_only(a, b, c, d=0, /):
    pass
position_only(1, 2, 3)  # OK
position_only(1, 2, c=3)  # raises exception
Traceback (most recent call last):
  File "<pyshell#11>", line 1, in <module>
    position_only(1,2,c=3)
TypeError: position_only() got some positional-only arguments passed as keyword arguments: 'c'</module></pyshell#11>

Shared memory for IPC

Now for interprocess communication python developer can use shared memory mechanism. Previously objects were pickled/unpickled and transported via socket. In python 3.8 new module called shared_memory were introduced in the multiprocessing package. Let's see how to use it:

from multiprocessing import shared_memory
a = shared_memory.ShareableList(range(5))
print(a.shm.name)
>>> 'wnsm_bd6b5302'

We use the name of the shared memory in order to connect to it using different python shell console:

from multiprocessing import shared_memory
b = shared_memory.ShareableList(name='wnsm_bd6b5302')
print(b)
>>> ShareableList([0, 1, 2, 3, 4], name='wnsm_bd6b5302')

Wow! Great feature indeed.

TypedDict

3.8 introduced TypedDict which is type annotation for values of fixed string keys dictionaries:

from typing import TypedDict

class Movie(TypedDict):
    title: str
    year: int

movie: Movie = {
    'title': 'Catch me if you can', 
    'year': 2002
}

Now you can use Movie to type annotations:

from typing import List

def my_function(films: List[Movie]):
    pass

final

Those of you who are familiar with Java already know what final means. For those who do not final prohibits changing an object. For example if you decorate you class with final, nobody should inherit from it.

from typing import Final, final

@final
class FinalClass:
    pass

# type checker will fail because you cannot inherit from FinalClass
class InheritedFromFinal(FinalClass):
    pass

You can declare the final variable as:

birth_year: Final = 1989
birth_year = 1901  # IDE/type checker will warn you that the value should not be changed

Now you can also prohibit method overloading:

class MyClass:
    @final
    def prohibited(self):
        pass

class SecondClass(MyClass):
    def prohibited(self):  # it is prohibited!!11
        pass

It is just one of my favourite features, if you would like to know more take a look at changelog.