Великолепный 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-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-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 позволяет писать более чистый код на уровне синтаксиса языка.
Форматируемые строковые литералы
С момента релиза 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'
Подчёркивания в числах
Возможно эта возможность в языке совсем и незначительная, но мне она очень нравится, так как теперь можно приводить большие числа в более читаемый вид:
# было a = 1000000 # стало b = 1_000_000
Новая реализация словарей
Начиная с 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