LINUX.ORG.RU

Python 3.7

 ,


5

8

Спустя полтора года после выхода предыдущей мажорной версии, наконец-то состоялся релиз Python 3.7.

В этом выпуске

  • Улучшена поддержка аннотации типов
  • Data classes
  • Атрибуты модулей
  • Отладка с помощью breakpoint()
  • И многое другое

PEP 563, Отложенное исполнение аннотаций типов

Теперь аннотации разрешаются в момент вызова функции, а не в момент загрузки её кода. Это уменьшает время старта программы и делает доступным использование имён, определённых позднее самой функции (forward references).

Такой код вызывал бы ошибку в предыдущих версиях Python

class C:
    @classmethod
    def from_string(cls, source: str) -> C:
        ...

    def validate_b(self, obj: B) -> bool:
        ...

class B:
    ...

Это изменение нарушает совместимость, поэтому до прихода версии Python 4.0 пока требует

from __future__ import annotations

PEP 553, Встроенная функция breakpoint()

Отладка стала ещё проще! Допустим, у вас есть такой код

def divide(e, f):
    return f / e

a, b = 0, 1
print(divide(a, b))

В предыдущих версиях для отладки вам требовалось:

def divide(e, f):
    import pdb; pdb.set_trace()
    return f / e

В 3.7 это выглядит проще и короче

def divide(e, f):
    breakpoint()
    return f / e

Теперь запускайте ваш код:

$ python3.7 bugs.py 
> /home/gahjelle/bugs.py(3)divide()
-> return f / e
(Pdb)

По умолчанию breakpoint() просто заменяется на import pdb; pdb.set_trace(), однако это можно изменить. Скажем, вы можете использовать другой отладчик:

$ PYTHONBREAKPOINT=pudb.set_trace python3.7 bugs.py
Или отключить отладку вовсе
$ PYTHONBREAKPOINT=0 python3.7 bugs.py
ZeroDivisionError: division by zero
Или запустить IPython
$ PYTHONBREAKPOINT=IPython.embed python3.7 bugs.py 
IPython 6.3.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: print(e / f)
0.0
В конечном счёте, вы можете написать свой собственный обработчик breakpoint()

PEP 557, Data Classes

Новый модуль dataclasses делает более удобным написание классов, основная задача которых — хранить данные. Вы просто используете декоратор, и весь бойлерплейт пишется за вас.

from dataclasses import dataclass, field

@dataclass(order=True)
class Country:
    name: str
    population: int
    area: float = field(repr=False, compare=False)
    coastline: float = 0

    def beach_per_person(self):
        """Meters of coastline per person"""
        return (self.coastline * 1000) / self.population

Методы __init__, __repr__, __eq__, __ne__, __lt__, __le__, __gt__, __ge__ будут сгенерированы автоматически для класса Country

PEP 562, Кастомизация атрибутов модулей

Вы уже давно знакомы с __getattr__ для классов. Теперь этот метод может быть определён и для модулей. Типичные примеры использования: сообщить о том, что некоторая функция в модуле объявлена deprecated, а также ленивая загрузка тяжелых подмодулей.

PEP 564, Временны́е функции с наносекундным разрешением

Улучшен модуль time, добавлено несколько новых функций

time.clock_gettime_ns()
time.clock_settime_ns()
time.monotonic_ns()
time.perf_counter_ns()
time.process_time_ns()
time.time_ns()
Точность расчёта временных интервалов повышена до наносекунд

Упорядоченные словари

Порядок ключей в словарях теперь гарантированно совпадает с порядком их вставки, это добавлено в спецификацию.

>>> {"one": 1, "two": 2, "three": 3}  # Python <= 3.5
{'three': 3, 'one': 1, 'two': 2}

>>> {"one": 1, "two": 2, "three": 3}  # Python >= 3.6
{'one': 1, 'two': 2, 'three': 3}

Это работало ещё с версии 3.6, однако опиралось на внутреннюю реализацию словарей CPython, и полагаться на такой порядок было нельзя.

Новые ключевые слова: async и await

Корутины с async и await были введены в Python 3.5, однако для обратной совмесимости всё ещё можно было объявить переменные с такими именами. Теперь это будет выдавать ошибку.

>>> async = 1
  File "<stdin>", line 1
    async = 1
          ^
SyntaxError: invalid syntax

>>> def await():
  File "<stdin>", line 1
    def await():
            ^
SyntaxError: invalid syntax

Улучшение модуля asyncio

Модуль asyncio для поддержки асинхронности был представлен в Python 3.4 (введение). В Python 3.7 asyncio получил большое количество новых функций, поддержку контекстных переменных и улучшения производительности. Например, используя asyncio.run(), вы можете легко вызывать корутины из синхронного кода, не создавая event loop.

import asyncio

async def hello_world():
    print("Hello World!")

asyncio.run(hello_world())

PEP 567, Контекстные переменные

Контекстные переменные — это переменные, которые могут иметь различные значения в зависимости от окружения. Они похожи на Thread-Local Storage, в которых каждый исполняемый тред может иметь разное значение переменной, однако контекстные переменные могут иметь разные значение даже в пределах одного треда. Основная область применения — параллельные асинхронные задачи.

import contextvars

name = contextvars.ContextVar("name")
contexts = list()

def greet():
    print(f"Hello {name.get()}")

# Construct contexts and set the context variable name
for first_name in ["Steve", "Dina", "Harry"]:
    ctx = contextvars.copy_context()
    ctx.run(name.set, first_name)
    contexts.append(ctx)

# Run greet function inside each context
for ctx in reversed(contexts):
    ctx.run(greet)

Запуск скрипта приветствует Steve, Dina, и Harry в обратном порядке:

$ python3.7 context_demo.py
Hello Harry
Hello Dina
Hello Steve

Импорт файлов с данными с помощью importlib.resources

Как происходила упаковка ресурсов в пакет до Python 3.7? Обычно выбирали один из трёх способов

  • Захардкоженные пути к ресурсам
  • Поместить файлы внурь пакета и получать к ним доступ с помощью __file__
  • Использовать setuptools.pkg_resources

Первый способ не портируем. Второй подходит лучше, но если Python-пакет находится внутрь zip архива, то там не будет атрибута __file__, что создает проблемы. Третий способ работает, однако слишком медленный.

Теперь появляется ещё один способ: новый модуль importlib.resources в стандартной библиотеке. Он использует уже существующую функциональность импорта модулей для загрузки файлов. Допустим, у вас есть ресурсы внутри пакета:

data/
│
├── alice_in_wonderland.txt
└── __init__.py

Теперь вы можете получить доступ к alice_in_wonderland.txt следующим образом:

>>> from importlib import resources
>>> with resources.open_text("data", "alice_in_wonderland.txt") as fid:
...     alice = fid.readlines()
... 
>>> print("".join(alice[:7]))
CHAPTER I. Down the Rabbit-Hole

Alice was beginning to get very tired of sitting by her sister on the
bank, and of having nothing to do: once or twice she had peeped into the
book her sister was reading, but it had no pictures or conversations in
it, ‘and what is the use of a book,’ thought Alice ‘without pictures or
conversations?’

Похожая функция resources.open_binary() открывает файлы в бинарном режиме.

Оптимизации

Ни один релиз Python не обходится без набора оптимизаций. Python 3.7 не стал исключением:

  • Снижены накладные расходы при вызове многих методов из стандартной библиотеки
  • В целом методы теперь вызываются на 20% быстрее
  • Время запуска самого Python снижено на 10-30%
  • Импортирование typing теперь быстрее в 7 раз.

Различные лучшения CPython

  • Уход от ASCII как от дефолтной кодировки:
  • PEP 552, Воспроизводимые .pycs
  • Новая опция -X
    $ python3.7 -X importtime my_script.py
    import time: self [us] | cumulative | imported package
    import time:      2607 |       2607 | _frozen_importlib_external
    ...
    import time:       844 |      28866 |   importlib.resources
    import time:       404 |      30434 | plugins
    
    Вы также можете использовать -X dev для активации «режима разработки» и -X utf8 для активации режима UTF-8. Полный список опций.
  • PEP 565, улучшенная обработка DeprecationWarning

>>> Новость на Real Python

>>> Официальный обзор изменений

Это тот язычок, где приватные поля - вовсе не приватные? Бугага!

И да - зачем в динамическом недоязычке добвили аннотации типов? Поняли, что статическая типизация рулит?

Python - defective by design.

FilosofeM ★★ ()
Ответ на: комментарий от tailgunner

Это тот язычок, в котором нет приватных полей.

Даже в пхп есть, а тут нет. Было б пофиг, если б его только для простеньких скриптов юзали. Так нет же, django-@$янго. Наверное это неизбежно как закон всемирного тяготения: какая б фигня не появись, обязательно найдутся фанатики, которые запихают её в каждую дырку затычкой, даже туда где ей вообще не место.

dimgel ()
Ответ на: комментарий от ism

Python очень продуманный и организовнный язык

Если б это было так, то в каждой версии не добавляли бы новые «фичи» прямо в язык. Да ещё и ломая совместимость.

no-such-file ★★★★★ ()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от no-such-file

Если б это было так, то в каждой версии не добавляли бы новые «фичи» прямо в язык. Да ещё и ломая совместимость.

Зачем ты лжешь про сломанную совместимость?

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

Зачем ты лжешь про сломанную совместимость

ЛОЛ ЧТО? Да тут же прямо в новости написано, что сломано и больше не работает как раньше. Я понимаю конечно, что шанс в это вляпаться небольшой, а те кто полагались на старое поведение СCЗБ, но факт-то остаётся.

no-such-file ★★★★★ ()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от anonymous

покажи мне реальный код с переменной async = 1

А чем async = 1 не реальный код? Чем он отличается от foo = 1? Расскажи мне почему я наперёд должен знать что там через пару лет взбредёт в голову разработчикам языка.

no-such-file ★★★★★ ()
Ответ на: комментарий от no-such-file

Если б это было так, то в каждой версии не добавляли бы новые «фичи» прямо в язык. Да ещё и ломая совместимость

Зачем ты лжешь про сломанную совместимость

ЛОЛ ЧТО?

Проблемы с пониманием текста? Повторю: зачем ты лжешь?

Да тут же прямо в новости написано, что сломано и больше не работает как раньше.

Не виляй. Ты лгал о сломанной совместимости в каждой версии.

И да, те, кто писали async = 1 - ССЗБ и должны страдать. Правда, пострадать сильно им не удастся, потому что ошибка выявляется компилятором.

tailgunner ★★★★★ ()
Ответ на: комментарий от no-such-file

Плять, раз в 10 лет добавили новый кейворд, ошибка, если она вдруг есть, фиксится сраным зедом. Никто кроме тебя тупо не заметил. Серьёзное что-то есть?

anonymous ()
Ответ на: комментарий от tailgunner

Повторю: зачем ты лжешь?

А ты зачем принимаешь героин?

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

У тебя после героина проблемы с восприятием речи? Вот у тебя на аватарке изображён непойми кто. Я тоже должен буквально понимать что это твоя рожа? Давай так, я признаю, что я «лгал» сказав что _буквально_ в каждой версии питона ломают совместимость, а ты признаешь что у тебя на аватарке _буквально_ твоё фото.

no-such-file ★★★★★ ()
Ответ на: комментарий от anonymous

Серьёзное что-то есть?

Нет конечно, но у фанбоев питона я смотрю бомбит серьёзно. Смешно, что я ведь нигде не говорил, что питон плохой, или его плохо развивают - это у фанбоев какие-то комплексы.

no-such-file ★★★★★ ()
Ответ на: комментарий от no-such-file

Я тоже должен буквально понимать что это твоя рожа?

Ты? Да, именно так ты и должен понимать.

Давай так, я признаю, что я «лгал» сказав что _буквально_ в каждой версии питона ломают совместимость

Да кому нафиг нужно твое признание.

tailgunner ★★★★★ ()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от no-such-file

ЛОЛ ЧТО?

Ты тоже в шары долбишься?

У тебя после героина проблемы с восприятием речи? Вот у тебя на аватарке изображён непойми кто. Я тоже должен буквально понимать что это твоя рожа?

у фанбоев питона я смотрю бомбит серьёзно

ага, серьёзно бомбит

anonymous ()
Ответ на: комментарий от t184256

Довольно скучный релиз

Data Classes мне показались приятной фичей, постоянные self.x = x, self.y = y уже оскомину набивали.

А с введением breakpoint я может быть наконец-то откажусь от старой доброй отладочной печати

Crocodoom ()
Ответ на: комментарий от sT331h0rs3

Кстати да, нафига Гвидо разрешил такой говнокод? Давно же изсвесто, что если аргументов больше полудюжины, то надо передавать их одним отдельным объектом. Вот и датаклассы завезли.

anonymous ()
Ответ на: комментарий от Crocodoom

постоянные self.x = x, self.y = y уже оскомину набивали

А разве это не решалось применением специального метакласса? КМК я что-то такое видел в Python Cookbook...

no-such-file ★★★★★ ()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от vertexua

Какая там теперь структура данных и какая сложность операций?

Моя вспоминать, что упорядоченные словари появились, когда в них какой-то более быстрый алгоритм вставили. Упорядоченность была побочным эффектом.

anonymous ()
Ответ на: комментарий от Shadow

Но ты правда написал фигню

Я зря написал про совместимость, у питонистов видимо триггер на это. А вот по поводу

Если б это было так, то в каждой версии не добавляли бы новые «фичи» прямо в язык

как-то все молчат, хотя это было главным посылом.

no-such-file ★★★★★ ()