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

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

★★★★★

Проверено: tailgunner ()
Последнее исправление: tailgunner (всего исправлений: 5)
Ответ на: комментарий от dimgel

Python очень продуманный и организовнный язык, на нем все делается гораздо быстрей. Если приватные поля не сделали значит были причины

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

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

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

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

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

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

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

Времена нынче неспокойные успевать надо за требованиями

Переезд же с одной версии на более высокую несложен

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

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

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

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

покажи мне реальный код с переменной async = 1, это каким дауном надо быть чтобы назвать так переменную

anonymous
()
Ответ на: комментарий от 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 ★★★★★
()
Ответ на: комментарий от tailgunner

И да, те, кто писали async = 1 - ССЗБ и должны страдать.

Неплохо переобулся.

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

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

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

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

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

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

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

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

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

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

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

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

ЛОЛ ЧТО?

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

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

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

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

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

Но ты правда написал фигню уровня «си Г..о, потому что там надо вручную памятью для переменных рулить»

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

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

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

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

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

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

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

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

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

Ну давай я скажу. Посыл неверен, одно про Фому, а другое про Ерёму. Про корутины популярные языки прочухались недавно. Как прочухались - так и добавили.

Признак непродуманности - это изменение старого. Как с юникодовыми стрингами.

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

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

Как они додумались до использования двойного подчёркивания (ака __main__) - я так и не понял.

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

Как они додумались до использования двойного подчёркивания (ака __main__) - я так и не понял.

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

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

Про корутины популярные языки прочухались недавно. Как прочухались - так и добавили

Про корутины популярные языки прочухались уже давно и запилили генераторы. В том числе и в питон.

Признак непродуманности - это изменение старого

Вот именно.

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

Про корутины популярные языки прочухались уже давно и запилили генераторы.

Ты намеренно сравниваешь сардельку с пальцем?

Про ленивые недоколлекции популярные языки прочухались раньше и запилили генераторы. В том числе не только питон.

До async/await допёрли позже. В том числе не только в питоне.

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

Ты намеренно сравниваешь сардельку с пальцем?

Я думал ты знаешь, что до async/await в asyncio использовались генераторы. Собственно и сейчас можно. Генераторы, это не только про «ленивые коллекции» если что.

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

Я думал ты знаешь, что до async/await в asyncio использовались генераторы.

Я знаю, что некоторые отморозки придумали так делать. Ещё я знаю, что название generator намекает. Отморозки в негативном, но восхищённом смысле, если что.

Это не отменяет, что потом прочухались и сделали нормально.

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

Пишет же варнинг в лог, а вообще потеря коллбека это детская ошибка, с практикой проходит.

import asyncio

async def func():
    print("test work")

async def main():
    print("enter")
    func()
    print("leave")

event_loop = asyncio.get_event_loop()
event_loop.run_until_complete(main())
$ python test.py 
enter
test.py:8: RuntimeWarning: coroutine 'func' was never awaited
  func()
leave

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

Варнинг это костыль. Я так понял этот RuntimeWarning поймать нельзя. Я бы для отладки лучше завершал программу. Вообще я так понял в c# и других языках с асинхронными функциями таких ошибок вообще нет.

Пишет же варнинг в лог, а вообще потеря коллбека это детская ошибка, с практикой проходит.

Не всякая асинхронная функция используется как коллбек.

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

Варнинг это костыль.

В чем костыльность то, предшественник asyncio twisted вообще молчал в такой ситуации. Тебе дали ключевое слово, синтаксический сахар, чтобы ты передал управление суперциклу (EventLoop), ты забыл его поставить и получил указатель на функцию, о чем и варнинг, интерпретатор же не знает тебя, может ты гуру питона и у тебя фабрика и ты на зымыканиях пораждаешь функциональщину.

Не всякая асинхронная функция используется как коллбек.

Налицо непонимание асинхронной парадигмы.

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

Генераторы, это не только про «ленивые коллекции» если что

Не от хорошей жизни.

WitcherGeralt ★★
()
Ответ на: комментарий от I-Love-Microsoft

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

Двойное подчёркивание - приватное поле. Одинарное - protected. Кого у вас там отсутствие?

anonymous
()
Ответ на: комментарий от I-Love-Microsoft

Приватные поля нарушают дзен питона: явное, лучше неявного. А так как одно из свойст питона это рефлексия, то есть возможность исследовать в рантайме, код и состояние интерпретатора, то уже из коробки есть способы посмотреть любое поле, любой структуры.

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

Лол ну что ты несешь, еще недавно то же самое говорили про выражение присваивания, и что? Вон недавно ввели. Только прошло >20 лет

loz ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.