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)

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

У каждого процесса есть как минимум один поток одна нить.

Не путай потоки с процессами. Смысл задания в том что в одном процессе у тебя должно быть 3 потока которые пытаются одновременно работать с одним списком. Ты на шелле это сможешь сделать?

Rodegast ★★★★★
()

Спасибо за новость. Нововведения впечатляют.

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

3 потока которые пытаются одновременно работать с одним списком

Интересно, на какой странице прозвучит то страшное слово из трех букв, после которого мечты и надежды питонистов рассыпаются в прах

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

Если ты про GIL, то он даже упрощает выполнение этого задания. А так, да многопоточность в python-е весьма условная.

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

Нафига я буду натягивать сову на глобус, если я могу выполнить задание быстро и в рамках семантики моего языка, отвечая при этом всем требованиям оригинального задания?

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

Нафига я буду натягивать сову на глобус

Ну ты же писал что у тебя всё работает, тогда какие проблемы?

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

а новых фич там всё равно нет, не будет и не надо...

Поддерживаю.

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

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

О мертвых или хорошо, или никак.

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

У меня работа. А у тебя, если ты такой внимательный, я просил алгоритм, который неплохо бы иметь в питоне, а не высосаную из пальца хрень, где многопоточность нафиг не сдалась.

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

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

У каждого процесса есть как минимум один поток одна нить.

Не путай потоки с процессами.

Я не путаю.

Смысл задания в том что в одном процессе у тебя должно быть 3 потока которые пытаются одновременно работать с одним списком. Ты на шелле это сможешь сделать?

Да, конечно. Это конвейер из 3-х программ.

А так, да многопоточность в python-е весьма условная.

В Python, конечно, GIL и всё такое, но для для распараллеливания задач I/O вполне хватает.

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

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

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

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

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

Yur4eg ★★
()

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

Десять лет ждал! Уже и писать на Питоне бросил, а всё равно сердце радуется. Долгих лет, поздравляю с релизом, закопайте 2.x.

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

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

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

GIL подвержен только питоно-байткод, а вот системные вызовы read/write замечательно будут работать в тредах.

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

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

И чем тебе моё задание не нравится. Предполагается что Файл в 1000000 строк быстро не прочитать, а пока его читают процессор простаивает. Вот тут многопоточность может вполне пригодится.

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

Смысл задания в том что в одном процессе у тебя должно быть 3 потока которые пытаются одновременно работать с одним списком. Ты на шелле это сможешь сделать?

Да, конечно. Это конвейер из 3-х программ.

Нет это не конвейер.

Обоснуй.

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

Список читается, фильтруется, сортируется; всё это происходит одновременно:

(while read l; do echo $l; done) | grep -v Regexp | sort

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

И чем тебе моё задание не нравится. Предполагается что Файл в 1000000 строк быстро не прочитать, а пока его читают процессор простаивает. Вот тут многопоточность может вполне пригодится.

Мне не нравится, что ты это делаешь на одной коллекции и в три потока.

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

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

Как ты намерен сортировать и фильтровать один список в два потока?

Сортировщик отсортирует мусор - фильтру придётся по всему списку его искать.

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

Обоснуй...Список читается, фильтруется, сортируется; всё это происходит одновременно

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

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

Мне не нравится, что ты это делаешь на одной коллекции и в три потока.
Как ты намерен сортировать и фильтровать один список в два потока?

Я рад что ты начинаешь понимать всю специфику многопоточности :) Для того что бы это делать на одной коллекции есть семафоры и прочая херня... Ну хорошо, сделай это для начала не на одной коллекции.

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

Он считывается и фильтруется одновременно, но для сортировки нужен весь список целиком

Нафиг? Бери с конца, вставляй в нужное место.

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

Я рад что ты начинаешь понимать всю специфику многопоточности :) Для того что бы это делать на одной коллекции есть семафоры и прочая херня... Ну хорошо, сделай это для начала не на одной коллекции.

Мьютексы, фьютексы. А ещё в питоне есть multiprocessing и Queue чтобы не трахать свои мозги без надобности. И если ты полез в семафоры, то у тебя должны быть на это веские причины, иначе не «мультитрединг в питоне - говно», а «я - сам себе злобный буратино».

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

Да, с совместимостью беда, особенно с кодами написанными на каболе.

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

для сортировки нужен весь список целиком,

Нет. Там merge sort, ему для начала сортировки не нужны все данные.

по этому она будет ждать пока он не будет прочитан и отфильтрован.

Не будет.

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

Потоки можно использовать в данной задаче немного по-другому:

1) Создать пул потоков

2) Разделить файл на N пар смещений начало-конец

3) Cчитать из файла данные каждым потоком - свои смещения, попутно удаляя в каждом потоке злополучные неверные значения

4) Синхронизировать потоки

5) Сделать конкатенацию списков, полученных от разных потоков

6) Отсортировать параллельным вариантом быстрой сортировки на созданном пуле потоков

Конечно, это не даст такую потенциально феерическую производительность, как ваш вариант с одновременным чтением, удалением и сортировкой, но такой вариант более предсказуем, он легче отлаживается и легче поддерживается, поскольку состоит из «условно индивидуальной» для данной задачи части - п.п. 1-5 и стандартного хорошо описанного алгоритма параллельной сортировки, который ещё и заменить можно модульно: не нравится один алгоритм - заменил 6-й этап другим алгоритмом.

Описанный вариант из 6-ти шагов, кстати, вполне реализуем на Shell.

И да, в данной задаче как таковое использование параллельных потоков по-моему имеет смысл только на этапе сортировки, потому что на этапе чтения файла первоначальная задержка ввода-вывода, если файл не в кеше файловой системы, будет, скорее всего на порядки больше времени, затрачиваемого на чтение из одного куска ОЗУ в другой. Я бы вообще подумал про mmap файла в данной задаче, а не про чтение из файлового дескриптора.

Т.е. ИМХО использование потоков на этапе чтения и фильтрации имеет явный смысл, если а) файл изначально замаплен в память и б) стоимость фильтрации является сколько-нибудь ощутимой. Впрочем, я не упомянул особенности работы контроллера памяти на современных материнских платах...

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

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

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

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

Нет. Там merge sort, ему для начала сортировки не нужны все данные.

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

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

Потоки можно использовать в данной задаче немного по-другому

Совершенно верно. Это можно сделать ещё проще и надёжнее, но я хотел заманить анонимуса в отладчик, и тогда бы он понял чем python плох для подобных задач.

Конечно, это не даст такую потенциально феерическую производительность, как ваш вариант с одновременным чтением, удалением и сортировкой

Наоборот ему пришлось бы ставить семафоры что делает процесс последовательным + возможны взаимные блокировки.

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

Если файл не нравится, то можно заменить его чтением из сети (кстати твой алгоритм с многопоточным чтением в этом случае сломается). Для целей задания это не столь важно.

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

А сортировка бинарным деревом? По-моему вариант, будет плохо только если данные исходно скорее отсортированы, чем нет. Со всякого рода логами, например, можно легко напороться. Т.е. нужно ребалансировку дерева делать по ходу его формирования.

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

Совершенно верно. Это можно сделать ещё проще и надёжнее, но я хотел заманить анонимуса в отладчик, и тогда бы он понял чем python плох для подобных задач.

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

Наоборот ему пришлось бы ставить семафоры что делает процесс последовательным + возможны взаимные блокировки.

Тебя пять философов вилками по лбу не били? Или ты считаешь, что били тебя одного?

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

2) Разделить файл на N пар смещений начало-конец

3) Cчитать из файла данные каждым потоком - свои смещения, попутно удаляя в каждом потоке злополучные неверные значения

Если я правильно понял, у меня вопрос. Допустим, значение это abcd.
И смещение выбрано таким образом, что оно разделит значение на ab и cd.
Следовательно ни один из потоков не увидит значение для удаления — abcd.
Как быть в таком случае?

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

питоновские трэды не нужны для решения такой задачи

не будет разницы, в один тред это делать или в три

трэды понадобились бы, например, если тебе надо читать из двух файлов одновременно (например, err и out)

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

Там merge sort, ему для начала сортировки не нужны все данные.

А это который список напополам делит

Нет. Кнута почитай.

tailgunner ★★★★★
()

Быстрее стал?

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

Лавры шамана покоя не дают?)

Я присоединился к проводимой Шаманом программе повышения ЧСВ грамотных юзеров.

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

Давно обогнал по скорости написания кода. Python - самый быстрый язык для написания прототипов.

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

А сортировка бинарным деревом?

Пожалуй это оптимальный вариант.

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

Проблемы, найденные «через жопу» сваливаются на «через жопу», а не на язык.

Жаль что ты не захотел прочувствовать многопоточную отладку... А что касается языка, то есть два способа поиска ошибок. Первый способ это отладка, а второй очень мощная статическая типизация. Первый способ это не про многопоточность/конкурентность, а второй не про python.

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

Жаль что ты не захотел прочувствовать многопоточную отладку...

Во первых, для твоей задачки отладчик не нужен от слова flash player. Во вторых, при чём тут питон?

А что касается языка, то есть два способа поиска ошибок. Первый способ это отладка, а второй очень мощная статическая типизация. Первый способ это не про многопоточность/конкурентность, а второй не про python.

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

Отладка - это процесс поиска и исправления ошибок по определению. Она не может быть способом. Отладчик и статическая типизация - это инструменты для отладки. Оба опциональны. И оба по определению не являются способами.

И да, я жду от тебя реализацию твоей задачи на произвольном яп. Тупо чтобы ты научился формулировать задачи.

anonymous
()

Ув. друзья, кто-нибудь знает, где взять / как собрать питон 3 под aix 7.2? Совершенно нет желания писать на встроенном в aix perl...

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

Pyhton 4.0 когда ждать?

Никогда. Ждулия вас всех убьёт.

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