Перейти к главному содержимому

Великолепный Python 3

В этой стате я опишу возможности Python 3, которые облегчают жизнь разработчика. Доработок в новой версии языка действительно много, поэтому я опишу только наиболее заметные изменения. Я пишу код на python каждый день, и ежедневное использование этих возможностей приносит мне большое удовольствие. Итак, поехали!

print теперь функция, а не оператор

Да, теперь print это функция, а не оператор, так что теперь необходимо использовать скобки: print("string"). Сигнатура функции такая:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

Подробнее в документации.

unicode по−умолчанию

Теперь все строки в Unicode по−умолчанию, а кодировка, конечно−же, utf-8. Искренне рад этому изменению, так как можно навсегда забыть про литерал u"" и писать более чистый код.

Числовой тип по−умолчанию — int

Да, теперь число при выполнении различных операций не может поменять свой тип и стать long, например. По−факту, long из Python 2 просто переименовали в int.

Документация (PEP-237).

Распаковка

В PEP-448 определены дополнительные возможности для использования операторов распаковки итератора и словаря (* и **). Их можно использовать произвольное количество раз, например:

>>> dict_a = {1: 'one'}
>>> dict_b = {2: 'two'}
>>> {**dict_a, **dict_b}
{1: 'one', 2: 'two'}

>>> list_a = [1, 2]
>>> list_b = [3, 4]
>>> [*list_a, *list_b]
[1, 2, 3, 4]

Так что можно обойтись без dict.update(another_dict). Работает, начиная с Python 3.5.

Ещё одно замечательное изменение в языке — расширенная распаковка. Теперь можно указать переменную, в которую будут помещены все элементы, не указанные явно. Проще пояснить на примере:

>>> a, *other, b = [1, 2, 3, 4, 5]
>>> a
1
>>> other
[2, 3, 4]
>>> b
5

Как видно, в переменную other попали все элементы, кроме первого и последнего.

Код стал более чистым (пример из документации):

# было
first, rest = seq[0], seq[1:]

# стало
first, *rest = seq

Настоящее деление

Наконец−то в Python 3 догадались реализовать настоящее деление. Ранее деление было неочевидным — для int и long возвращалась целая часть, а для float — приблизительный результат деления:

>>> 12 / 7
1
>>> 12 / 7.0
1.7142857142857142

Разумеется такое поведение по−умолчанию приводило к ошибкам в работе программ, когда на вход подавалось целое число (int, long) вместо дробного. Теперь эту ситуацию исправили и деление с помощью оператора / возвращает ожидаемый результат.

Документация (PEP-238).

Только ключевые аргументы

PEP-3102 определяет новый вид аргументов, которые могут быть переданы в функцию только по отдельному ключевому слову, но не через позиционный параметр. Суть в том, что ранее нельзя было определить аргументы переменной длины (*args), а за ними какие−то ключевые аргументы. Это было синтаксической ошибкой. Чтобы её обойти, приходилось определять сигнатуру функции как

def f(*args, **kwargs)

и получать ключевые аргументы уже оттуда, например как x = kwargs.get('x'). Теперь эта проблема решена и доступна вот такая запись:

def a(*args, key=None):
    pass

def b(a, b, *, key=None):
    pass

То есть Python 3 позволяет писать более чистый код на уровне синтаксиса языка.

Документация (PEP-3102).

Форматируемые строковые литералы

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

>>> name = "Fred"
>>> f"He said his name is {name}."
'He said his name is Fred.'
>>> width = 10
>>> precision = 4
>>> value = decimal.Decimal("12.34567")
>>> f"result: {value:{width}.{precision}}"  # nested fields
'result:      12.35'

Документация (PEP-498).

Подчёркивания в числах

Возможно эта возможность в языке совсем и незначительная, но мне она очень нравится, так как теперь можно приводить большие числа в более читаемый вид:

# было
a = 1000000

# стало
b = 1_000_000

Документация (PEP-515).

Новая реализация словарей

Начиная с Python 3.6 появилась новая реализация словарей, которая уменьшает объём потребляемой памяти на 20-25% по сравнению с версией 3.5.

Так же реализация словаря в Python 3.6 сохраняет порядок атрибутов, но это всего лишь деталь реализации интерпретатора CPython. То есть, в Pypy или любой другой версии интерпретатора словарь может быть не упорядоченным, что приведёт к ошибкам в программе.

Однако теперь гарантируется сохранение порядка определения атрибутов, а так же порядок элементов в **kwargs соответствует порядку, в котором эти элементы переданы в функцию.

Подробнее в документации.

Возможность модификации подкласса без использования метаклассов

Появилась возможность писать классы, которые изменяют поведение своих подклассов. По сути, этот функционал похож на написание декоратора класса, с тем отличием, что влияет он на все будущие подклассы, а не на один конкретный класс. Суть в том, что какие−то простые вещи, такие как, реестр подклассов, теперь можно реализовать без использования метаклассов.

class PluginBase:
    _plugins = {}

    def __init_subclass__(cls, *, name, **kwargs):
        cls._plugins[name] = cls
        super().__init_subclass__(**kwargs)

    @classmethod
    def get_plugin(cls, name):
        return cls._known_plugins[name]

class FooPlugin(Plugin, name="foo_plugin"):
    pass

В данном примере, при инициализации подкласса FooPlugin, выполняется метод __init_subclass__. Переменная cls указывает на сам инициализируемый подкласс. Далее информация о новом подклассе записывается в переменную _plugins базового класса (см. Python Data Model / method resolution order). Ну, и обратите внимание, что при инициализации подкласса на его поведение можно влиять с помощью параметров **kwargs.

Документация.

Заключение

На самом деле в Python есть огромное количество других нововведений и улучшений, но в данной статье я перечислил только самые важные для меня. За кадром остались type hints, new style classes, улучшения в поддержке асинхронного программирования и много чего ещё. Для ознакомления с ними рекомендую почитать What's new in Python, там действительно много интересного.

Комментарии

Comments powered by Disqus