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

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

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

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

Я думаю, что это скорее для foo(*args)

Да вроде как это и раньше работало

pairs = [(x, x) for x in range(1000)]

columns = list(zip(*pairs))

print(columns[0])

Проверь на Python3 ниже 3.7

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

Лишнее телодвижение. Вообще рандомный словарь изкоробки был наркоманским решением. А вот ордеред это ожидаемо и очевидно.

entefeed ☆☆☆ ()
Ответ на: комментарий от vertexua

Почему вы отвечаете вопросом на вопрос? Аргументированно объяснить «бомбаж» всего офиса вы не можете?

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

Когда у всех нормальных людей hash map с O(1) вставкой, удалением и изменением, у них какая-то интересная структура данных, в которой скорее всего все намного медленнее, но совсем не ясно зачем. Может я пропустил какой-то суперсовременный алгоритм 21го века, который быстрее или компактнее hash map, да и еще и порядок сохраняет? Если кто знает, называйте, почитаю. Я даже могу представить как все еще пользоваться hash map, но отдельно хранить порядок. Только это будет жрать отдельную память для очень сомнительной фичи, которую особо никто не просил

vertexua ★★★☆☆ ()

В новые dataclasses внезапно не завезли сереализацию в JSON у меня почему-то это подразумевалось.

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

Быстрее чем hash map?

Загугли сам, ну. Что помню, то написал.

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

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

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

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

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

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

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

Ну у них оно как-то не прозрачно если честно. В официальной документации ничего не написано. Есть страница на какой-то вики со сложностями операций, но похоже до этого изменения.

В С++ пишут сложность, когда структура называется не непосредственно «hash map»

http://www.cplusplus.com/reference/unordered_map/unordered_map/

В Java/Rust - просто так и пишут, HashMap. Все понятно и просто

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

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

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

RazrFalcon ★★★★★ ()

Кто бы мог подумать, что простенький язычок для скриптинга, развившийся из ещё более простенького язычка для обучения алгоритмам ABC, превратится в этакую современную помесь COBOL'а и PL/1.

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

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

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

anonymous ()

занятно, вот только не понятно что будет за мешанина в коде используя всё это многообразие синтаксического сахара.

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

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

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

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

Вот именно.

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

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

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

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

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

anonymous ()

Перешли на гоу, пистон не вставляет.

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

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

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

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

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

я для этого обычно подобный класс делаю и от него наследуюсь:

https://github.com/actionless/pikaur/blob/master/pikaur/core.py#L23-L40

https://github.com/actionless/pikaur/blob/master/pikaur/core.py#L49-L65

но идея с декоратором прикольная, надо будет переписать на Data Classes когда 3.7 прийдет в рачик

actionless ★★★★★ ()

ну теперь qbasic-у точно капец

buratino ★★★★ ()

Python все больше и больше скатывается в «не нужно».

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

Вообще не нужно.

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

Я с ужасом представляю что этот dataclasses может сгенерировать.

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

Этой фишкой ещё длительное время нельзя будет пользоваться т.к. это сломает совместимость с интерпретаторами предыдущих версий.

Новые ключевые слова: async и await, Улучшение модуля asyncio

Асинхронность / многопоточность это не про python.

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

Python2 официально больше не поддерживается, выводы делай сам.

С чего ты это взял?

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

Недавно новость была про последний релиз во второй ветке. Лень искать.

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

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

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

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

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

Недавно новость была про последний релиз во второй ветке.

Вторая ветка официально поддерживается до 2020 года. Не путай это с последним релизом.

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

шапка с дебианом ещё лет 5 поддерживать будут, а новых фич там всё равно нет, не будет и не надо...

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

Асинхронность / многопоточность это не про python.

умвр

А ещё я по несколько процессов форкаю.

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

Асинхронность / многопоточность это не про python.

умвр

А ты попробуй написать какой-то более менее сложный алгоритм с многопоточностью и потом его отладить. Надеюсь что после этого ты поймёшь про что я писал.

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

А ты попробуй написать какой-то более менее сложный алгоритм с многопоточностью и потом его отладить.

Давай пример более менее сложного алгоритма с многопоточностью, который имеет смысл иметь в питоне, пожалуйста. Авось на выходных потренеруюсь.

anonymous ()

Обычно в питонячьей нитке присутствуют упоминания руби.
Но эта нить не такая. Она — другая.

blackst0ne ★★★★★ ()

как же мне нравится простота языка и эластичность спецификации Python

anonymous ()

В Amazon Lambda не приехало. Закапывайте.

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

Типа «не поставил пробел - и оно начало работать невесть как»?

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

Обычно в питонячьей нитке присутствуют упоминания руби.

Так он же сдох?

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

Давай пример более менее сложного алгоритма с многопоточностью, который имеет смысл иметь в питоне, пожалуйста. Авось на выходных потренеруюсь.

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

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

Но зачем писать такую фигню на Python? Это однострочник на шелле.

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

Это однострочник на шелле.

На шелле есть потоки?

Rodegast ★★★★★ ()

Такими темпами в 202х будет 4 версия.

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

Конечно. У каждого процесса есть как минимум один поток одна нить. Ты не знал?

Так зачем писать эту фигню на Python?

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

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

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

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

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