What's new in Python 3.8?

In this article, you will learn how to apply assignment expressions to improve your code, benefit from positional-only arguments and how f-strings can be useful in debugging.

New Features in Python 3.8

Assignment expressions

New helpful “:=” notation called  “walrus operator” (formally "Assignment Expressions") implemented by Emily Morehouse, Python Core Developer and Founder has been added. It creates a way to assign values to variables as a part of an expression. 

if (list_length := len(sample_list) > x:
print(f"The list with {list_length} elements is longer than {x}")

It can also improve the experience with while looping through computing value to test loop termination:

sample_list = [1, 2, 3]while element := len(sample_list):
sample_list.pop(element - 1)

Another use case arrives in list comprehension when a filtered value is needed in the expression body:

[username for name in names if (username := f"user_{name}") in usernames]

There are however some cases where assignment expressions are not recommended, in other cases it must be parenthesized, mostly to avoid user confusion.

y := f(x) # incorrect
(y := f(x)) # not recommendeddef foo(bar = x := 1): # not correct
...
def foo(bar=(x := 1)): # nor recommended
...

Specific example of application in f-strings:

>>> f'{(x:=10)}' # uses assignment expression
'10'
>>> x = 10
>>> f'{x:=10}' # passes value to formatter
' 10'

As a “walrus operator” can be used in contexts where assignment statements are illegal like lambdas and comprehensions it doesn’t support advanced features, including multiple targets, iterable packing and unpacking and augmented assignment.

Positional-only parameters

It’s the new syntax to express that some function params must be specified positionally and cannot be used as keyword arguments. It was initially proposed by Guido van Rossum in 2012 and gives more control to library authors over the intended usage of an API and secures backward-compatibility. It’s worth taking a note that processing positional params is faster than kwargs.

def name(positional_only_parameters, /, positional_or_keyword_parameters,
*, keyword_only_parameters):

Self-documenting expressions in f-strings

In case you need to expand a text of f-string expression to evaluate its representation you can now use “=”, what is particularly helpful in debugging.

>>> user = 'merixstudio'
>>> born = date(2000, 1, 1)
>>> f'{user=} {born=}'
"user='merixstudio' member_since=datetime.date(2000, 1, 1)"

Reversible dictionaries

Dictionaries in Python were rewritten in Python 3.6, using a new implementation contributed by the PyPy project. In addition to being faster and more compact, dictionaries now have inherent ordering for their elements; they’re ordered as they are added, much as with lists. Python 3.8 Dict and dictviews are now iterable in reversed insertion order using reversed().

Unittest changes

Added AsyncMock to support an asynchronous version of Mock. 
Added addModuleCleanup() and addClassCleanup() to unittest to support cleanups for setUpModule() and setUpClass().

Several mock assert functions now also print a list of actual calls upon failure.

unittest module gained support for coroutines to be used as test cases with unittest.IsolatedAsyncioTestCase.

Example:

import unittest
class TestRequest(unittest.IsolatedAsyncioTestCase): async def asyncSetUp(self):
self.connection = await AsyncConnection() async def test_get(self):
response = await self.connection.get("https://example.com")
self.assertEqual(response.status_code, 200) async def asyncTearDown(self):
await self.connection.close()
if __name__ == "__main__":
unittest.main()

Typing growing up

Python’s typing system has already evolved quite significantly, however, there are some features added to improve narrow typing

TypedDict

A dictionary type with per-key types. TypedDict uses only string keys. By default, every key is required to be present. You can specify total=False to allow keys to be optional.

class Employee(TypedDict, total=False):
company: str
salary: float
competences: list

Literal types

A type that can be used to indicate to type checkers that the corresponding variable or function parameter has a value equivalent to the provided literal (or one of several literals)

def get_status(port: int) -> Literal['connected', 'disconnected']:
...
def validate_simple(data: Any) -> Literal[True]: # always returns True
...MODE = Literal['r', 'rb', 'w', 'wb']
def open_helper(file: str, mode: MODE) -> str:
...open_helper('/some/path', 'r') # Passes type check
open_helper('/other/path', 'typo') # Error in type checker

Final

A special typing construct to indicate to type checkers that a name cannot be re-assigned or overridden in a subclass.

MAX_SIZE: Final = 9000
MAX_SIZE += 1 # Error reported by type checkerclass Connection:
TIMEOUT: Final[int] = 10class FastConnector(Connection):
TIMEOUT = 1 # Error reported by type checker

Performance improvements in Python 3.8

Let's take a look at the performance improvements that come with the new Python release:

  1. A lot of built-in methods and functions have been sped up by 20% to 50%, as many of them were unnecessarily converting arguments passed to them.
  2. A new opcode cache can speed up certain instructions in the interpreter. However, the only currently implemented speed-up is for the LOAD_GLOBAL opcode, now 40% faster. Similar optimizations are planned for later versions of Python.
  3. File copying operations, such as shutil.copyfile() and shutil.copytree(), now use platform-specific calls and other optimizations to speed up operations.
  4. Newly created lists are now, on average, 12% smaller than before, thanks to optimizations that make use of the length of the list constructor object if it is known beforehand.
  5. Writes to class variables on new-style classes (e.g., class A(object)) are much faster in Python 3.8.
  6. operator.itemgetter() and collections.namedtuple() also have new speed optimizations.

Bump up?

You may raise a question of whether you should update Python to version 3.8 in a production environment? The new release brings several optimizations that help run code faster and reduce memory usage. For example, looking up in ‘namedtuple’ is significantly quicker also lists made of known-length iterables perform better. Upgrading from 3.7 should be seamless, as beta versions have been around for a while but it’s a good idea to check out.
 

Navigate the changing IT landscape

Some highlighted content that we want to draw attention to to link to our other resources. It usually contains a link .