Вам интересно, почему вам следует переходить с Python 3.6 на Python 3.7 или любую другую комбинацию версий? Или вы думаете о поддержке Python 3.5 и хотите знать, каких функций вам следует избегать? Тогда это ваша статья.

Конечно, есть гораздо больше возможностей. Но именно на них я спотыкаюсь чаще всего.

Pyenv

Прежде чем мы начнем вдаваться в подробности, вы должны знать о pyenv. Это очень удобный инструмент, позволяющий легко переключить версию Python. Он загружает их автоматически для вас. Вот как вы это используете:

# See which Python versions are available:
$ pyenv install --list
# Install one
$ pyenv install 3.5.9
# Use one:
$ pyenv local 3.5.9

Довольно удобно, что он переключает также инструменты, которые вы устанавливаете вместе с ним. Например, когда вы переключаетесь на 3.5.9, у вас также есть pip для этой версии.

Python 3.5

Я очень надеюсь, что никто больше не использует версии Python ниже 3.3. Или, не дай бог, хоть Python 2.7 😨.

В Python 3 так много новых функций и улучшений по сравнению с 2.7:

# python2 thinks this is fine, python3 throws an Exception
>>> True = False
>>> max(['foo', 2])
'foo'
>>> 'foo' > 2
True
# Advanced iterable unpacking:
a, b, *rest = range(10)

И это еще не все:

Также имейте в виду, что Python 2.7, Python 3.1 / 3.2 / 3.3 и 3.4 давно подошли к концу. А Python 3.5 достигнет этого в сентябре 2020 года (исходник).

Python 3.6

# Reasonable type annotation syntax
>>> from typing import List
>>> number : List[int] = [28, 4, 1990]
# f-string!
>>> bar = 3
>>> f"foo {bar}"
'foo 3'
# PEP 515: Underscores in Numeric Literals
>>> number = 1_000_000

Список новых возможностей Python 3.6 намного длиннее. Следует отметить одно улучшение: внутреннее представление словарей стало более эффективным, что привело к уменьшению размера памяти на 20%.

Python 3.7

Будущие аннотации очень удобны, когда вы хотите правильно аннотировать свои классы. Это предотвращает оценку аннотаций во время выполнения. Это означает, что если вы хотите вернуть класс Foo в методе этого класса, теперь вы можете это сделать. Раньше приходилось возвращать строку "Foo":

from __future__ import annotations
class Foo:
    def __init__(self, bar):
        self.bar = bar
    def foo(bar) -> Foo:
        self.bar = bar + bar
        return self
  • Словари имеют порядок вставки (исходник)
  • async и await - зарезервированные ключевые слова (источник)
  • PEP-557: Классы данных

Python 3.8

# f-strings for debugging
>>> bar = 3
>>> foo = "Hello World"
>>> f"{foo=}, {bar=}"
"foo='Hello World', bar=3"
# Assignment expressions (aka: The Walrus Operator)
>>> a = 6
>>> if is_positive := a > 0:
...     print("It's positive!")
... else:
...     print("It's negative")
... 
It's positive!

TypedDict тоже неплохой (пример взят из PEP-589):

from typing import TypedDict
class Movie(TypedDict):
    name: str
    year: int
movie: Movie = {'name': 'Blade Runner',
                'year': 1982}

Есть еще:

Python 3.9

PEP 584: Словарь Союза

>>> a = {'foo': 'bar', 42: 1337}
>>> b = {'x': 'y', 'a': 'b', 'c': 'd', 'foo': 'foo'}
>>> a | b
{'foo': 'foo', 42: 1337, 'x': 'y', 'a': 'b', 'c': 'd'}
>>> b | a
{'x': 'y', 'a': 'b', 'c': 'd', 'foo': 'bar', 42: 1337}

Python 3.10

PEP 618 - это график выпуска Python 3.10, который показывает, что он приближается!

Мы будем получать более качественные сообщения об ошибках (PEP 626), и это здорово! Мы также получили улучшения для аннотаций типов 🎉

Слон в комнате структурного сопоставления с образцом (PEP 634, PEP 635, PEP 636). Следующий пример взят из PEP 636:

# Before structural pattern matching
command = input("What are you doing next? ")
command_parts = command.split()
if len(command_parts) == 1:
    if command_parts[0] == "quit":
        print("Goodbye!")
        quit_game()
    elif command_parts[0] == "look":
        current_room.describe()
elif len(command_parts) == 2:
    if command_parts[0] == "get":
        obj = command_parts[1]
        character.get(obj, current_room)
    elif command_parts[0] == "go":
        direction = command_parts[1]
        current_room = current_room.neighbor(direction)
# With structural pattern matching
command = input("What are you doing next? ")
match command.split():
    case ["quit"]:
        print("Goodbye!")
        quit_game()
    case ["look"]:
        current_room.describe()
    case ["get", obj]:
        character.get(obj, current_room)
    case ["go", direction]:
        current_room = current_room.neighbor(direction)