Содержание страницы
Что нового в Python 3.2¶What’s New In Python 3.2
| Автор: | Рэймонд Хеттингер |
|---|
В этой статье описаны новые возможности Python 3.2 по сравнению с версией 3.1. Она сосредоточена на нескольких ключевых моментах и приводит несколько примеров. Полные сведения см. в файле Misc/NEWS.
См. также
PEP 392 - График выпуска Python 3.2
PEP 384: Определение стабильного ABI¶PEP 384: Defining a Stable ABI
Раньше модули расширения, собранные для одной версии Python, часто были несовместимы с другими версиями. Особенно в Windows каждый выпуск с новыми возможностями требовал пересборки всех модулей расширения, которые хотелось использовать. Это было следствием свободного доступа к внутренним структурам интерпретатора Python, который могли использовать модули расширения.
В Python 3.2 появляется альтернативный подход: модули расширения, ограничивающие себя ограниченным API (определяя Py_LIMITED_API), не могут использовать многие внутренние структуры, но ограничены набором функций API, которые обещают быть стабильными на протяжении нескольких выпусков. В результате модули расширения, собранные для 3.2 в этом режиме, будут также работать с 3.3, 3.4 и так далее. Модули расширения, использующие детали структур памяти, по-прежнему можно собирать, но их придётся перекомпилировать для каждого выпуска с новыми возможностями.
См. также
- PEP 384 - Определение стабильного ABI
- PEP написан Мартином фон Лёвисом.
PEP 389: Модуль разбора командной строки argparse¶PEP 389: Argparse Command Line Parsing Module
Новый модуль для разбора командной строки, argparse, был представлен, чтобы преодолеть ограничения optparse, который не обеспечивал поддержку позиционных аргументов (не только опций), подкоманд, обязательных опций и других распространённых шаблонов задания и проверки опций.
Этот модуль уже получил широкое распространение в сообществе как сторонний модуль. Будучи более функциональным, чем его предшественник, модуль argparse теперь является предпочтительным модулем для обработки командной строки. Старый модуль по-прежнему доступен из-за значительного объёма унаследованного кода, который от него зависит.
Вот пример аннотированного парсера, показывающий такие возможности, как ограничение результатов набором вариантов, указание metavar в справке, проверка наличия одного или нескольких позиционных аргументов и создание обязательной опции:
import argparse
parser = argparse.ArgumentParser(
description = 'Manage servers', # основное описание для справки
epilog = 'Tested on Solaris and Linux') # отображается после справки
parser.add_argument('action', # имя аргумента
choices = ['deploy', 'start', 'stop'], # три допустимых значения
help = 'action on each target') # сообщение справки
parser.add_argument('targets',
metavar = 'HOSTNAME', # имя переменной, используемое в сообщении справки
nargs = '+', # требуется одна или несколько целей
help = 'url for target machines') # пояснение к сообщению справки
parser.add_argument('-u', '--user', # опция -u или --user
required = True, # сделать его обязательным аргументом
help = 'login as user')
Пример вызова парсера для командной строки:
>>> cmd = 'deploy sneezy.example.com sleepy.example.com -u skycaptain'
>>> result = parser.parse_args(cmd.split())
>>> result.action
'deploy'
>>> result.targets
['sneezy.example.com', 'sleepy.example.com']
>>> result.user
'skycaptain'
Пример автоматически сгенерированной справки парсера:
>>> parser.parse_args('-h'.split())
usage: manage_cloud.py [-h] -u USER
{deploy,start,stop} HOSTNAME [HOSTNAME ...]
Manage servers
positional arguments:
{deploy,start,stop} action on each target
HOSTNAME url for target machines
optional arguments:
-h, --help show this help message and exit
-u USER, --user USER login as user
Tested on Solaris and Linux
Особенно удобная возможность argparse – это возможность определять подпарсеры, каждый со своими собственными схемами аргументов и отображением справки:
import argparse
parser = argparse.ArgumentParser(prog='HELM')
subparsers = parser.add_subparsers()
parser_l = subparsers.add_parser('launch', help='Launch Control') # first subgroup
parser_l.add_argument('-m', '--missiles', action='store_true')
parser_l.add_argument('-t', '--torpedos', action='store_true')
parser_m = subparsers.add_parser('move', help='Move Vessel', # second subgroup
aliases=('steer', 'turn')) # equivalent names
parser_m.add_argument('-c', '--course', type=int, required=True)
parser_m.add_argument('-s', '--speed', type=int, default=0)
$ ./helm.py --help # top level help (launch and move)
$ ./helm.py launch --help # help for launch options
$ ./helm.py launch --missiles # set missiles=True and torpedos=False
$ ./helm.py steer --course 180 --speed 5 # set movement parameters
См. также
- PEP 389 - Новый модуль разбора командной строки
- PEP написан Стивеном Бетардом.
Обновление кода optparse – подробнее о различиях с optparse.
PEP 391: Конфигурация логирования на основе словарей¶PEP 391: Dictionary Based Configuration for Logging
Модуль logging предлагал два вида конфигурации: один стиль с вызовами функций для каждой опции, другой стиль на основе внешнего файла, сохранённого в формате ConfigParser. Эти варианты не обеспечивали гибкости для создания конфигураций из файлов JSON или YAML, а также не поддерживали инкрементальную конфигурацию, которая необходима для указания параметров логгера из командной строки.
Для поддержки более гибкого стиля модуль теперь предлагает logging.config.dictConfig() для задания конфигурации логирования с помощью обычных словарей Python. Параметры конфигурации включают форматтеры, обработчики, фильтры и логгеры. Вот рабочий пример словаря конфигурации:
{"version": 1,
"formatters": {"brief": {"format": "%(levelname)-8s: %(name)-15s: %(message)s"},
"full": {"format": "%(asctime)s %(name)-15s %(levelname)-8s %(message)s"}
},
"handlers": {"console": {
"class": "logging.StreamHandler",
"formatter": "brief",
"level": "INFO",
"stream": "ext://sys.stdout"},
"console_priority": {
"class": "logging.StreamHandler",
"formatter": "full",
"level": "ERROR",
"stream": "ext://sys.stderr"}
},
"root": {"level": "DEBUG", "handlers": ["console", "console_priority"]}}
Если этот словарь сохранён в файле с именем conf.json, его можно загрузить и вызвать с помощью такого кода:
>>> import json, logging.config
>>> with open('conf.json') as f:
conf = json.load(f)
>>> logging.config.dictConfig(conf)
>>> logging.info("Transaction completed normally")
INFO : root : Transaction completed normally
>>> logging.critical("Abnormal termination")
2011-02-17 11:14:36,694 root CRITICAL Abnormal termination
См. также
- PEP 391 – Конфигурация логирования на основе словарей
- PEP написан Винаем Саджипом.
PEP 3148: Модуль concurrent.futures ¶PEP 3148: The concurrent.futures module
Код для создания параллельного выполнения и управления им собирается в новом пространстве имён верхнего уровня concurrent. Первый его компонент – пакет futures, предоставляющий единый высокоуровневый интерфейс для управления потоками и процессами.
Дизайн concurrent.futures был вдохновлён пакетом java.util.concurrent. В этой модели выполняющийся вызов и его результат представлены объектом Future, который абстрагирует возможности, общие для потоков, процессов и удалённых вызовов процедур. Этот объект поддерживает проверку состояния (выполняется или завершён), тайм-ауты, отмены, добавление колбэков, а также доступ к результатам или исключениям.
Основная часть нового модуля – два класса исполнителей для запуска и управления вызовами. Цель исполнителей – упростить использование существующих инструментов для параллельных вызовов. Они избавляют от необходимости настраивать пул ресурсов, запускать вызовы, создавать очередь результатов, добавлять обработку таймаутов и ограничивать общее количество потоков, процессов или удалённых вызовов.
В идеале каждое приложение должно использовать один общий исполнитель для нескольких компонентов, чтобы ограничения на процессы и потоки управлялись централизованно. Это решает проблему проектирования, возникающую, когда у каждого компонента своя конкурирующая стратегия управления ресурсами.
Оба класса имеют общий интерфейс с тремя методами: submit() для планирования вызываемого объекта и возврата объекта Future; map() для планирования множества асинхронных вызовов за раз, и shutdown() для освобождения ресурсов. Класс является менеджером контекста и может использоваться в операторе with, чтобы гарантировать автоматическое освобождение ресурсов, когда текущие ожидающие future завершат выполнение.
Простой пример ThreadPoolExecutor – это запуск четырёх параллельных потоков для копирования файлов:
import concurrent.futures, shutil
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as e:
e.submit(shutil.copy, 'src1.txt', 'dest1.txt')
e.submit(shutil.copy, 'src2.txt', 'dest2.txt')
e.submit(shutil.copy, 'src3.txt', 'dest3.txt')
e.submit(shutil.copy, 'src4.txt', 'dest4.txt')
См. также
- PEP 3148 – Futures – асинхронное выполнение вычислений
- PEP написан Брайаном Куинланом.
Код для параллельного чтения URL в потоках – пример использования потоков для параллельной загрузки нескольких веб-страниц.
Код для вычисления простых чисел параллельно, пример, демонстрирующий ProcessPoolExecutor.
PEP 3147: Директории репозитория PYC¶PEP 3147: PYC Repository Directories
Схема кэширования байт-кода Python в файлы .pyc плохо работала в средах с несколькими интерпретаторами Python. Если один интерпретатор встречал кэшированный файл, созданный другим, он перекомпилировал исходный код и перезаписывал кэш, теряя преимущества кэширования.
Проблема «pyc-войн» стала более заметной, поскольку в дистрибутивах Linux стало обычным делом поставлять несколько версий Python. Эти конфликты возникают и с альтернативными реализациями CPython, такими как Unladen Swallow.
Чтобы решить эту проблему, механизм импорта Python был расширен для использования разных имён файлов для каждого интерпретатора. Вместо того чтобы Python 3.2, Python 3.3 и Unladen Swallow конкурировали за файл с именем «mymodule.pyc», теперь они будут искать «mymodule.cpython-32.pyc», «mymodule.cpython-33.pyc» и «mymodule.unladen10.pyc». А чтобы все эти новые файлы не засоряли исходные каталоги, файлы pyc теперь собираются в каталог «__pycache__», расположенный внутри каталога пакета.
Помимо имён файлов и целевых каталогов, новая схема имеет несколько аспектов, видимых программисту:
У импортируемых модулей теперь есть атрибут __cached__, в котором хранится имя файла, который был фактически импортирован:
>>> import collections >>> collections.__cached__ 'c:/py32/lib/__pycache__/collections.cpython-32.pyc'
Тег, уникальный для каждого интерпретатора, доступен из модуля imp:
>>> import imp >>> imp.get_tag() 'cpython-32'
Скрипты, которые пытаются определить имя исходного файла из импортированного файла, теперь должны быть умнее. Больше недостаточно просто удалить букву «c» из имени файла «.pyc». Вместо этого используйте новые функции в модуле imp:
>>> imp.source_from_cache('c:/py32/lib/__pycache__/collections.cpython-32.pyc') 'c:/py32/lib/collections.py' >>> imp.cache_from_source('c:/py32/lib/collections.py') 'c:/py32/lib/__pycache__/collections.cpython-32.pyc'
Модули py_compile и compileall были обновлены для отражения нового соглашения об именовании и целевого каталога. Командная строка вызова compileall имеет новые опции: -i для указания списка файлов и каталогов для компиляции и -b, которая приводит к записи байт-кода в их устаревшее расположение, а не в __pycache__.
Модуль importlib.abc обновлён и теперь содержит новые абстрактные базовые классы для загрузки файлов байт-кода. ABC PyLoader и PyPycLoader объявлены устаревшими (инструкции по сохранению совместимости с Python 3.1 приведены в документации).
См. также
- PEP 3147 – Директории репозитория PYC
- PEP написан Барри Варшавой.
PEP 3149: .so-файлы с тегом версии ABI¶PEP 3149: ABI Version Tagged .so Files
Директория репозитория PYC позволяет размещать несколько кэшированных файлов байт-кода в одном месте. Этот PEP реализует аналогичный механизм для разделяемых объектных файлов, помещая их в общую директорию с разными именами для каждой версии.
Общая директория называется «pyshared», а имена файлов различаются указанием реализации Python (например, CPython, PyPy, Jython и т.д.), номерами старшей и младшей версии, а также необязательными флагами сборки (например, «d» для отладки, «m» для pymalloc, «u» для wide-unicode). Для произвольного пакета «foo» при установке дистрибутивного пакета можно увидеть такие файлы:
/usr/share/pyshared/foo.cpython-32m.so
/usr/share/pyshared/foo.cpython-33md.so
В самом Python теги доступны из функций модуля sysconfig:
>>> import sysconfig
>>> sysconfig.get_config_var('SOABI') # найти тег версии
'cpython-32mu'
>>> sysconfig.get_config_var('EXT_SUFFIX') # найти полное расширение имени файла
'.cpython-32mu.so'
См. также
- PEP 3149 – файлы .so с тегами версии ABI
- PEP написан Барри Варшавой.
PEP 3333: Python Web Server Gateway Interface v1.0.1¶
Этот информационный PEP проясняет, как проблемы байтов/текста должны обрабатываться протоколом WSGI. Сложность в том, что обработка строк в Python 3 наиболее удобно выполняется с помощью типа str, хотя сам протокол HTTP ориентирован на байты.
PEP различает так называемые нативные строки, используемые для заголовков и метаданных запросов/ответов, и байтовые строки, используемые для тел запросов и ответов.
Нативные строки всегда имеют тип str, но ограничены кодовыми точками от U+0000 до U+00FF, которые преобразуются в байты с помощью кодировки Latin-1. Эти строки используются для ключей и значений в словаре окружения, а также для заголовков ответа и статусов в функции start_response(). Они должны следовать RFC 2616 в отношении кодировки. То есть они должны быть либо символами ISO-8859-1, либо использовать RFC 2047 кодировку MIME.
Для разработчиков, переносящих WSGI-приложения с Python 2, вот ключевые моменты:
- Если приложение уже использовало строки для заголовков в Python 2, никаких изменений не требуется.
- Если же приложение кодировало выходные заголовки или декодировало входные заголовки, то заголовки необходимо будет перекодировать в Latin-1. Например, выходной заголовок, закодированный в utf-8 с использованием h.encode('utf-8'), теперь нужно преобразовать из байтов в нативные строки с помощью h.encode('utf-8').decode('latin-1').
- Значения, возвращаемые приложением или отправляемые с помощью метода write(), должны быть байтовыми строками. Функция start_response() и переменная environ должны использовать нативные строки. Их нельзя смешивать.
Для разработчиков серверов, пишущих шлюзы CGI-to-WSGI или другие протоколы в стиле CGI, пользователи должны иметь возможность доступа к окружению с помощью нативных строк, даже если базовая платформа использует другие соглашения. Чтобы устранить этот разрыв, модуль wsgiref содержит новую функцию wsgiref.handlers.read_environ() для перекодирования переменных CGI из os.environ в нативные строки и возврата нового словаря.
См. также
- PEP 3333 – Python Web Server Gateway Interface v1.0.1
- PEP написан Филлипом Иби.
Прочие изменения языка ¶Other Language Changes
Некоторые небольшие изменения, внесённые в ядро языка Python:
Форматирование строк для format() и str.format() получило новые возможности для символа формата #. Ранее для целых чисел в двоичной, восьмеричной или шестнадцатеричной системе он приводил к добавлению префикса '0b', '0o' или '0x' соответственно. Теперь он также может обрабатывать числа с плавающей запятой, комплексные и Decimal, что приводит к тому, что вывод всегда содержит десятичную точку, даже если после неё нет цифр.
>>> format(20, '#o') '0o24' >>> format(12.34, '#5.0f') ' 12.'
(Предложено Марком Дикинсоном и реализовано Эриком Смитом в issue 7094.)
Также появился новый метод str.format_map(), расширяющий возможности существующего метода str.format() за счёт возможности принимать произвольные объекты mapping (отображения). Этот новый метод позволяет использовать форматирование строк с любыми объектами, похожими на словарь, такими как defaultdict, Shelf, ConfigParser или dbm. Он также полезен с пользовательскими подклассами dict, которые нормализуют ключи перед поиском или предоставляют метод __missing__() для неизвестных ключей:
>>> import shelve >>> d = shelve.open('tmp.shl') >>> 'The {project_name} status is {status} as of {date}'.format_map(d) 'The testing project status is green as of February 15, 2011' >>> class LowerCasedDict(dict): def __getitem__(self, key): return dict.__getitem__(self, key.lower()) >>> lcd = LowerCasedDict(part='widgets', quantity=10) >>> 'There are {QUANTITY} {Part} in stock'.format_map(lcd) 'There are 10 widgets in stock' >>> class PlaceholderDict(dict): def __missing__(self, key): return '<{}>'.format(key) >>> 'Hello {name}, welcome to {location}'.format_map(PlaceholderDict()) 'Hello <name>, welcome to <location>'
(Предложено Рэймондом Хеттингером и реализовано Эриком Смитом в issue 6081.)
Интерпретатор теперь можно запускать с тихой опцией -q, чтобы предотвратить отображение информации об авторских правах и версии в интерактивном режиме. Эту опцию можно проверить с помощью атрибута sys.flags:
$ python -q >>> sys.flags sys.flags(debug=0, division_warning=0, inspect=0, interactive=0, optimize=0, dont_write_bytecode=0, no_user_site=0, no_site=0, ignore_environment=0, verbose=0, bytes_warning=0, quiet=1)
(Предложено Марчином Войдыром в issue 1772833).
Функция hasattr() работает путём вызова getattr() и определения, возникает ли исключение. Этот метод позволяет ей обнаруживать методы, созданные динамически с помощью __getattr__() или __getattribute__(), которые в противном случае отсутствовали бы в словаре класса. Ранее hasattr перехватывал любое исключение, возможно маскируя настоящие ошибки. Теперь hasattr был сужен и перехватывает только AttributeError, позволяя другим исключениям проходить:
>>> class A: @property def f(self): return 1 // 0 >>> a = A() >>> hasattr(a, 'f') Traceback (most recent call last): ... ZeroDivisionError: integer division or modulo by zero
(Обнаружено Юрием Селивановым и исправлено Бенджамином Петерсоном; issue 9666.)
Результат str() для числа с плавающей точкой или комплексного числа теперь совпадает с его repr(). Ранее форма str() была короче, но это лишь вызывало путаницу и больше не нужно, поскольку теперь по умолчанию отображается максимально короткое repr():
>>> import math >>> repr(math.pi) '3.141592653589793' >>> str(math.pi) '3.141592653589793'
(Предложено и реализовано Марком Дикинсоном; issue 9337.)
Объекты memoryview теперь имеют метод release() и поддерживают протокол контекстного менеджера. Это позволяет своевременно освобождать любые ресурсы, полученные при запросе буфера от исходного объекта.
>>> with memoryview(b'abcdefgh') as v: print(v.tolist()) [97, 98, 99, 100, 101, 102, 103, 104]
(Добавлено Антуаном Питру; issue 9757.)
Ранее было запрещено удалять имя из локального пространства имён, если оно встречается как свободная переменная во вложенном блоке:
def outer(x): def inner(): return x inner() del x
Теперь это разрешено. Помните, что цель предложения except очищается, так что этот код, который работал в Python 2.6, вызывал SyntaxError в Python 3.1, а теперь снова работает:
def f(): def print_error(): print(e) try: something except Exception as e: print_error() # неявное "del e" здесь
(См. issue 4617.)
Внутренний инструмент structsequence теперь создаёт подклассы tuple. Это означает, что C-структуры, такие как возвращаемые os.stat(), time.gmtime() и sys.version_info, теперь работают как именованный кортеж и взаимодействуют с функциями и методами, ожидающими кортеж в качестве аргумента. Это большой шаг вперёд в деле придания C-структурам такой же гибкости, как у их аналогов на чистом Python:
>>> isinstance(sys.version_info, tuple) True >>> 'Version %d.%d.%d %s(%d)' % sys.version_info 'Version 3.2.0 final(0)'
(Предложено Арфревером Фретесом Тайферсаром Арахезисом и реализовано Бенджамином Петерсоном в issue 8413.)
Предупреждения теперь легче контролировать с помощью переменной окружения PYTHONWARNINGS в качестве альтернативы использованию -W в командной строке:
$ export PYTHONWARNINGS='ignore::RuntimeWarning::,once::UnicodeWarning::'
(Предложено Барри Варшавой и реализовано Филипом Дженви в issue 7301.)
Добавлена новая категория предупреждений ResourceWarning. Она возникает при обнаружении потенциальных проблем с потреблением ресурсов или очисткой. По умолчанию она отключена в обычных сборках, но может быть включена средствами модуля warnings или из командной строки.
ResourceWarning выдаётся при завершении интерпретатора, если список gc.garbage не пуст, и если установлен gc.DEBUG_UNCOLLECTABLE, то выводятся все несобираемые объекты. Это предназначено для того, чтобы программист осознавал, что его код содержит проблемы с финализацией объектов.
ResourceWarning также выдаётся, когда файловый объект уничтожается без явного закрытия. Хотя деаллокатор такого объекта гарантирует закрытие базового ресурса операционной системы (обычно файлового дескриптора), задержка в деаллокации может вызвать различные проблемы, особенно в Windows. Вот пример включения предупреждения из командной строки:
$ python -q -Wdefault >>> f = open("foo", "wb") >>> del f __main__:1: ResourceWarning: unclosed file <_io.BufferedWriter name='foo'>(Добавлено Антуаном Питру и Георгом Брандлем в issue 10093 и issue 477863.)
Объекты range теперь поддерживают методы index и count. Это часть работы по обеспечению полной реализации collections.Sequence абстрактного базового класса. В результате язык получит более единообразный API. Кроме того, объекты range теперь поддерживают срезы и отрицательные индексы, даже со значениями больше sys.maxsize. Это делает range более совместимым со списками:
>>> range(0, 100, 2).count(10) 1 >>> range(0, 100, 2).index(10) 5 >>> range(0, 100, 2)[5] 10 >>> range(0, 100, 2)[0:5] range(0, 10, 2)
(Предложено Дэниелом Штуцбахом в issue 9213, Александром Белопольским в issue 2690 и Ником Коглан в issue 10889.)
Встроенная функция callable() из Py2.x была воскрешена. Она предоставляет краткую, читаемую альтернативу использованию абстрактного базового класса в выражении вида isinstance(x, collections.Callable):
>>> callable(max) True >>> callable(20) False
(См. issue 10518.)
Механизм импорта Python теперь может загружать модули, установленные в каталогах, в именах путей которых есть не-ASCII символы. Это решило давнюю проблему с домашними каталогами пользователей, имеющих не-ASCII символы в именах.
(Потребовало обширной работы Виктора Стиннера в issue 9425.)
Новые, улучшенные и устаревшие модули¶New, Improved, and Deprecated Modules
Стандартная библиотека Python прошла значительную работу по сопровождению и улучшению качества.
Самая большая новость для Python 3.2 в том, что пакет email, модули mailbox и nntplib теперь корректно работают с моделью bytes/text в Python 3. Впервые обеспечена правильная обработка сообщений со смешанными кодировками.
По всей стандартной библиотеке уделено больше внимания вопросам кодировок и различиям между текстом и байтами. В частности, взаимодействие с операционной системой теперь лучше обменивается не-ASCII данными, используя кодировку Windows MBCS, локаль-зависимые кодировки или UTF-8.
Ещё одно важное достижение – добавление значительно улучшенной поддержки SSL-соединений и сертификатов безопасности.
Кроме того, больше классов теперь реализуют менеджер контекста для поддержки удобной и надёжной очистки ресурсов с помощью оператора with.
email¶
Удобство использования пакета email в Python 3 было в значительной степени восстановлено благодаря обширным усилиям Р. Дэвида Мюррея. Проблема заключалась в том, что электронные письма обычно читаются и хранятся в виде bytes, а не str текста, и они могут содержать несколько кодировок в одном письме. Поэтому пакет email пришлось расширить для разбора и генерации сообщений в формате bytes.
Новые функции message_from_bytes() и message_from_binary_file(), а также новые классы BytesFeedParser и BytesParser позволяют разбирать двоичные данные сообщений в объекты модели.
При вводе байтов в модель get_payload() по умолчанию будет декодировать тело сообщения с Content-Transfer-Encoding равным 8bit, используя кодировку, указанную в MIME-заголовках, и вернёт результирующую строку.
При вводе байтов в модель Generator будет преобразовывать тела сообщений с Content-Transfer-Encoding равным 8bit, чтобы вместо него использовалось 7bit Content-Transfer-Encoding.
Заголовки с незакодированными не-ASCII байтами считаются закодированными по RFC 2047 с использованием набора символов unknown-8bit.
Новый класс BytesGenerator создаёт вывод в виде байтов, сохраняя любые неизменённые не-ASCII данные, присутствовавшие во входных данных, использованных для построения модели, включая тела сообщений с Content-Transfer-Encoding равным 8bit.
Класс smtplib SMTP теперь принимает строку байтов в качестве аргумента msg для метода sendmail(), а новый метод send_message() принимает объект Message и может опционально получать адреса from_addr и to_addrs непосредственно из объекта.
(Предложено и реализовано Р. Дэвидом Мюрреем, issue 4661 и issue 10321.)
elementtree¶
Пакет xml.etree.ElementTree и его аналог xml.etree.cElementTree были обновлены до версии 1.3.
Добавлено несколько новых полезных функций и методов:
- xml.etree.ElementTree.fromstringlist() – строит XML-документ из последовательности фрагментов
- xml.etree.ElementTree.register_namespace() для регистрации глобального префикса пространства имён
- xml.etree.ElementTree.tostringlist() для строкового представления, включающего все подсписки
- xml.etree.ElementTree.Element.extend() для добавления последовательности из нуля или более элементов
- xml.etree.ElementTree.Element.iterfind() ищет элемент и дочерние элементы
- xml.etree.ElementTree.Element.itertext() создаёт итератор текста по элементу и его дочерним элементам
- xml.etree.ElementTree.TreeBuilder.end() закрывает текущий элемент
- xml.etree.ElementTree.TreeBuilder.doctype() обрабатывает объявление doctype
Два метода устарели:
- xml.etree.ElementTree.getchildren() используйте list(elem) вместо этого.
- xml.etree.ElementTree.getiterator() используйте Element.iter вместо этого.
Подробнее об обновлении см. в статье Introducing ElementTree на сайте Фредрика Лунда.
(Предложено Florent Xicluna и Fredrik Lundh, issue 6472.)
functools¶
Модуль functools включает новый декоратор для кэширования вызовов функций. functools.lru_cache() позволяет сохранять результаты повторных запросов к внешнему ресурсу, если ожидается, что они будут одинаковыми.
Например, добавление декоратора кеширования к функции запроса к базе данных может сократить количество обращений к базе данных для популярных поисковых запросов:
>>> import functools >>> @functools.lru_cache(maxsize=300) >>> def get_phone_number(name): c = conn.cursor() c.execute('SELECT phonenumber FROM phonelist WHERE name=?', (name,)) return c.fetchone()[0]
>>> for name in user_requests: get_phone_number(name) # cached lookup
Чтобы помочь с выбором эффективного размера кеша, обёрнутая функция оснащается средствами отслеживания статистики кеша:
>>> get_phone_number.cache_info() CacheInfo(hits=4805, misses=980, maxsize=300, currsize=300)
Если таблица phonelist обновляется, устаревшее содержимое кеша можно очистить с помощью:
>>> get_phone_number.cache_clear()
(Предложено Raymond Hettinger с использованием идей дизайна от Jim Baker, Miki Tebeka и Nick Coghlan; см. recipe 498245, recipe 577479, issue 10586 и issue 10593.)
Декоратор functools.wraps() теперь добавляет атрибут __wrapped__, указывающий на исходную вызываемую функцию. Это позволяет интроспектировать обёрнутые функции. Он также копирует __annotations__, если она определена. И теперь он корректно пропускает отсутствующие атрибуты, такие как __doc__, которые могут быть не определены для обёрнутой вызываемой функции.
В приведённом выше примере кеш можно удалить, восстановив исходную функцию:
>>> get_phone_number = get_phone_number.__wrapped__ # некэшированная функция
(Авторы: Nick Coghlan и Terrence Cole; issue 9567, issue 3445 и issue 8814.)
Чтобы упростить написание классов с методами полного сравнения, новый декоратор functools.total_ordering() использует существующие методы равенства и неравенства для заполнения остальных методов.
Например, указание __eq__ и __lt__ позволит total_ordering() добавить __le__, __gt__ и __ge__:
@total_ordering class Student: def __eq__(self, other): return ((self.lastname.lower(), self.firstname.lower()) == (other.lastname.lower(), other.firstname.lower())) def __lt__(self, other): return ((self.lastname.lower(), self.firstname.lower()) < (other.lastname.lower(), other.firstname.lower()))
С помощью декоратора total_ordering остальные методы сравнения заполняются автоматически.
(Автор: Raymond Hettinger.)
Чтобы облегчить перенос программ с Python 2, функция functools.cmp_to_key() преобразует старую функцию сравнения в современную функцию ключа:
>>> # порядок сортировки с учётом локали >>> sorted(iterable, key=cmp_to_key(locale.strcoll))
Примеры сортировки и краткое руководство по сортировке см. в руководстве Sorting HowTo.
(Автор: Raymond Hettinger.)
itertools¶
Модуль itertools имеет новую функцию accumulate(), созданную по образцу оператора scan из APL и функции accumulate из Numpy:
>>> from itertools import accumulate >>> list(accumulate([8, 2, 50])) [8, 10, 60]
>>> prob_dist = [0.1, 0.4, 0.2, 0.3] >>> list(accumulate(prob_dist)) # кумулятивное распределение вероятностей [0.1, 0.5, 0.7, 1.0]
Пример использования accumulate() см. в примерах для модуля random.
(Автор: Raymond Hettinger с учётом предложений по дизайну от Mark Dickinson.)
collections¶
Класс collections.Counter теперь имеет две формы вычитания на месте: существующий оператор -= для насыщающего вычитания и новый метод subtract() для обычного вычитания. Первый подходит для мультимножеств, которые имеют только положительные счётчики, а второй больше подходит для случаев, допускающих отрицательные счётчики:
>>> tally = Counter(dogs=5, cat=3) >>> tally -= Counter(dogs=2, cats=8) # насыщающее вычитание >>> tally Counter({'dogs': 3})
>>> tally = Counter(dogs=5, cats=3) >>> tally.subtract(dogs=2, cats=8) # обычное вычитание >>> tally Counter({'dogs': 3, 'cats': -5})
(Автор: Raymond Hettinger.)
Класс collections.OrderedDict имеет новый метод move_to_end(), который принимает существующий ключ и перемещает его в первую или последнюю позицию упорядоченной последовательности.
По умолчанию элемент перемещается в последнюю позицию. Это эквивалентно обновлению записи с помощью od[k] = od.pop(k).
Быстрая операция перемещения в конец полезна для изменения порядка следования записей. Например, упорядоченный словарь можно использовать для отслеживания порядка доступа, упорядочивая записи от самых старых к самым недавно запрошенным.
>>> d = OrderedDict.fromkeys(['a', 'b', 'X', 'd', 'e']) >>> list(d) ['a', 'b', 'X', 'd', 'e'] >>> d.move_to_end('X') >>> list(d) ['a', 'b', 'd', 'e', 'X']
(Автор: Raymond Hettinger.)
Класс collections.deque получил два новых метода: count() и reverse(), что делает их более взаимозаменяемыми с объектами list:
>>> d = deque('simsalabim') >>> d.count('s') 2 >>> d.reverse() >>> d deque(['m', 'i', 'b', 'a', 'l', 'a', 's', 'm', 'i', 's'])
(Автор: Raymond Hettinger.)
threading¶
Модуль threading имеет новый класс синхронизации Barrier, который заставляет несколько потоков ждать, пока все они не достигнут общей точки барьера. Барьеры полезны для того, чтобы задача с несколькими предусловиями не запускалась, пока все предшествующие задачи не будут завершены.
Барьеры могут работать с произвольным числом потоков. Это обобщение механизма рандеву, который определён только для двух потоков.
Реализованные как двухфазный циклический барьер, объекты Barrier подходят для использования в циклах. Отдельные фазы заполнения и опустошения гарантируют, что все потоки будут освобождены (опустошены) до того, как любой из них сможет вернуться и войти в барьер снова. Барьер полностью сбрасывается после каждого цикла.
Пример использования барьеров:
from threading import Barrier, Thread
def get_votes(site):
ballots = conduct_election(site)
all_polls_closed.wait() # не подсчитывать, пока все голосования не закрыты
totals = summarize(ballots)
publish(site, totals)
all_polls_closed = Barrier(len(sites))
for site in sites:
Thread(target=get_votes, args=(site,)).start()
В этом примере барьер обеспечивает правило, что голоса не могут быть подсчитаны на любом избирательном участке, пока все участки не закроются. Обратите внимание, что решение с барьером похоже на решение с threading.Thread.join(), но потоки остаются живыми и продолжают работать (подводить итоги голосования) после пересечения точки барьера.
Если какая-либо из предшествующих задач может зависнуть или быть задержана, барьер можно создать с необязательным параметром timeout. Тогда, если время ожидания истечёт до того, как все предшествующие задачи достигнут точки барьера, все ожидающие потоки освобождаются и возбуждается исключение BrokenBarrierError:
def get_votes(site):
ballots = conduct_election(site)
try:
all_polls_closed.wait(timeout = midnight - time.now())
except BrokenBarrierError:
lockbox = seal_ballots(ballots)
queue.put(lockbox)
else:
totals = summarize(ballots)
publish(site, totals)
В этом примере барьер обеспечивает более надежное правило. Если некоторые избирательные участки не заканчивают работу до полуночи, барьер срабатывает по тайм-ауту, и бюллетени опечатываются и помещаются в очередь для последующей обработки.
Смотрите Barrier Synchronization Patterns для получения дополнительных примеров использования барьеров в параллельных вычислениях. Кроме того, простое и подробное объяснение барьеров приведено в The Little Book of Semaphores, раздел 3.6.
(Предложено Kristján Valur Jónsson с проверкой API от Jeffrey Yasskin в issue 8777.)
datetime and time¶
Модуль datetime теперь имеет новый тип timezone, который реализует интерфейс tzinfo, возвращая фиксированное смещение UTC и название часового пояса. Это упрощает создание объектов datetime с учётом часового пояса:
>>> from datetime import datetime, timezone >>> datetime.now(timezone.utc) datetime.datetime(2010, 12, 8, 21, 4, 2, 923754, tzinfo=datetime.timezone.utc) >>> datetime.strptime("01/01/2000 12:00 +0000", "%m/%d/%Y %H:%M %z") datetime.datetime(2000, 1, 1, 12, 0, tzinfo=datetime.timezone.utc)
Кроме того, объекты timedelta теперь можно умножать на float и делить на float и int. И объекты timedelta теперь можно делить друг на друга.
Метод datetime.date.strftime() больше не ограничен годами после 1900. Новый поддерживаемый диапазон лет – от 1000 до 9999 включительно.
Когда в кортеже времени используется год из двух цифр, его интерпретация определяется time.accept2dyear. По умолчанию True, что означает, что для двузначного года столетие подбирается по правилам POSIX, управляющим форматом %y strptime.
Начиная с Py3.2, использование эвристики подбора столетия будет вызывать DeprecationWarning. Вместо этого рекомендуется установить time.accept2dyear в False, чтобы можно было использовать большие диапазоны дат без угадывания:
>>> import time, warnings >>> warnings.resetwarnings() # удалить фильтры предупреждений по умолчанию >>> time.accept2dyear = True # угадать, означает ли 11 число 11 или 2011 >>> time.asctime((11, 1, 1, 12, 34, 56, 4, 1, 0)) Warning (from warnings module): ... DeprecationWarning: Century info guessed for a 2-digit year. 'Fri Jan 1 12:34:56 2011' >>> time.accept2dyear = False # использовать полный диапазон допустимых дат >>> time.asctime((11, 1, 1, 12, 34, 56, 4, 1, 0)) 'Fri Jan 1 12:34:56 11'
Несколько функций теперь имеют значительно расширенные диапазоны дат. Когда time.accept2dyear имеет значение false, функция time.asctime() будет принимать любой год, помещающийся в C int, в то время как функции time.mktime() и time.strftime() будут принимать полный диапазон, поддерживаемый соответствующими функциями операционной системы.
(Предложено Александром Белопольским и Виктором Штиннером в выпуске 1289118, выпуске 5094, выпуске 6641, выпуске 2706, выпуске 1777412, выпуске 8013, и выпуске 10827.)
math¶
Модуль math был обновлён и теперь содержит шесть новых функций, вдохновлённых стандартом C99.
Функция isfinite() предоставляет надёжный и быстрый способ обнаружения особых значений. Она возвращает True для обычных чисел и False для Nan или Infinity:
>>> [isfinite(x) for x in (123, 4.56, float('Nan'), float('Inf'))]
[True, True, False, False]
Функция expm1() вычисляет e**x-1 для малых значений x без потери точности, которая обычно сопровождает вычитание почти равных величин:
>>> expm1(0.013671875) # более точный способ вычисления e**x-1 для малых x
0.013765762467652909
Функция erf() вычисляет интеграл вероятности или функцию ошибок Гаусса. Дополнительная функция ошибок, erfc(), равна 1 - erf(x):
>>> erf(1.0/sqrt(2.0)) # доля нормального распределения в пределах одного стандартного отклонения
0.682689492137086
>>> erfc(1.0/sqrt(2.0)) # доля нормального распределения за пределами одного стандартного отклонения
0.31731050786291404
>>> erf(1.0/sqrt(2.0)) + erfc(1.0/sqrt(2.0))
1.0
Функция gamma() является непрерывным расширением факториала. Подробнее см. http://en.wikipedia.org/wiki/Gamma_function. Поскольку функция связана с факториалами, она быстро растёт даже при малых значениях x, поэтому существует также функция lgamma() для вычисления натурального логарифма гамма-функции:
>>> gamma(7.0) # шесть факториал
720.0
>>> lgamma(801.0) # логарифм факториала 800
4551.950730698041
(Автор: Mark Dickinson.)
abc ¶
Модуль abc теперь поддерживает abstractclassmethod() и abstractstaticmethod().
Эти инструменты позволяют определить абстрактный базовый класс, который требует реализации определённого classmethod() или staticmethod():
class Temperature(metaclass=abc.ABCMeta):
@abc.abstractclassmethod
def from_fahrenheit(cls, t):
...
@abc.abstractclassmethod
def from_celsius(cls, t):
...
(Патч предоставлен Дэниелом Урбаном; выпуск 5867.)
io¶
У io.BytesIO появился новый метод getbuffer(), который предоставляет функциональность, аналогичную memoryview(). Он создаёт редактируемое представление данных без создания копии. Произвольный доступ к буферу и поддержка срезов хорошо подходят для редактирования на месте:
>>> REC_LEN, LOC_START, LOC_LEN = 34, 7, 11
>>> def change_location(buffer, record_number, location):
start = record_number * REC_LEN + LOC_START
buffer[start: start+LOC_LEN] = location
>>> import io
>>> byte_stream = io.BytesIO(
b'G3805 storeroom Main chassis '
b'X7899 shipping Reserve cog '
b'L6988 receiving Primary sprocket'
)
>>> buffer = byte_stream.getbuffer()
>>> change_location(buffer, 1, b'warehouse ')
>>> change_location(buffer, 0, b'showroom ')
>>> print(byte_stream.getvalue())
b'G3805 showroom Main chassis '
b'X7899 warehouse Reserve cog '
b'L6988 receiving Primary sprocket'
(Предложено Антуаном Питру в выпуске 5506.)
reprlib¶
При написании метода __repr__() для пользовательского контейнера легко забыть обработать случай, когда элемент ссылается обратно на сам контейнер. Встроенные объекты Python, такие как list и set, обрабатывают самоссылки, отображая ”...” в рекурсивной части строки представления.
Чтобы упростить написание таких методов __repr__(), в модуле reprlib появился новый декоратор recursive_repr() для обнаружения рекурсивных вызовов __repr__() и подстановки вместо них строки-заполнителя:
>>> class MyList(list):
@recursive_repr()
def __repr__(self):
return '<' + '|'.join(map(repr, self)) + '>'
>>> m = MyList('abc')
>>> m.append(m)
>>> m.append('x')
>>> print(m)
<'a'|'b'|'c'|...|'x'>
(Предложено Рэймондом Хеттингером в выпуске 9826 и выпуске 9840.)
logging¶
В дополнение к описанной выше конфигурации на основе словаря пакет logging содержит множество других улучшений.
Документация по logging была дополнена базовым руководством, продвинутым руководством и поваренной книгой с рецептами логирования. Эти документы – самый быстрый способ изучить логирование.
Функция настройки logging.basicConfig() получила аргумент style для поддержки трёх различных типов форматирования строк. По умолчанию используется “%” для традиционного %-форматирования, может быть установлено “{” для нового стиля str.format(), или “$” для форматирования в стиле оболочки, предоставляемого string.Template. Следующие три конфигурации эквивалентны:
>>> from logging import basicConfig
>>> basicConfig(style='%', format="%(name)s -> %(levelname)s: %(message)s")
>>> basicConfig(style='{', format="{name} -> {levelname} {message}")
>>> basicConfig(style='$', format="$name -> $levelname: $message")
Если до возникновения события логирования не задана конфигурация, теперь используется конфигурация по умолчанию с StreamHandler, направленным в sys.stderr, для событий уровня WARNING и выше. Ранее событие, возникшее до настройки конфигурации, либо вызывало исключение, либо молча отбрасывалось в зависимости от значения logging.raiseExceptions. Новый обработчик по умолчанию хранится в logging.lastResort.
Использование фильтров было упрощено. Вместо создания объекта Filter предикатом может быть любой вызываемый объект Python, возвращающий True или False.
Было сделано множество других улучшений, повышающих гибкость и упрощающих конфигурацию. Полный список изменений в Python 3.2 смотрите в документации модуля.
csv¶
Модуль csv теперь поддерживает новый диалект, unix_dialect, который применяет кавычки для всех полей и использует традиционный стиль Unix с '\n' в качестве разделителя строк. Зарегистрированное имя диалекта – unix.
У csv.DictWriter появился новый метод writeheader() для записи начальной строки с названиями полей:
>>> import csv, sys
>>> w = csv.DictWriter(sys.stdout, ['name', 'dept'], dialect='unix')
>>> w.writeheader()
"name","dept"
>>> w.writerows([
{'name': 'tom', 'dept': 'accounting'},
{'name': 'susan', 'dept': 'Salesl'}])
"tom","accounting"
"susan","sales"
(Новый диалект предложен Джеем Талботом в выпуске 5975, а новый метод предложен Эдом Абрахамом в выпуске 1537721.)
contextlib¶
Появился новый и немного умопомрачительный инструмент ContextDecorator, который полезен для создания менеджера контекста, выполняющего двойную роль декоратора функции.
Для удобства эта новая функциональность используется contextmanager(), поэтому не требуется дополнительных усилий для поддержки обеих ролей.
Основная идея в том, что и менеджеры контекста, и декораторы функций могут использоваться для обёрток до и после действия. Менеджеры контекста оборачивают группу инструкций с помощью оператора with, а декораторы функций оборачивают группу инструкций, заключённых в функцию. Поэтому иногда возникает необходимость написать обёртку до или после действия, которую можно использовать в любой роли.
Например, иногда полезно оборачивать функции или группы инструкций логгером, который может отслеживать время входа и время выхода. Вместо того чтобы писать и декоратор функции, и менеджер контекста для этой задачи, contextmanager() предоставляет обе возможности в одном определении:
from contextlib import contextmanager
import logging
logging.basicConfig(level=logging.INFO)
@contextmanager
def track_entry_and_exit(name):
logging.info('Entering: {}'.format(name))
yield
logging.info('Exiting: {}'.format(name))
Ранее это можно было использовать только как менеджер контекста:
with track_entry_and_exit('widget loader'):
print('Some time consuming activity goes here')
load_widget()
Теперь его можно использовать и как декоратор:
@track_entry_and_exit('widget loader')
def activity():
print('Some time consuming activity goes here')
load_widget()
Попытка выполнять две роли одновременно накладывает некоторые ограничения на технику. Менеджеры контекста обычно имеют возможность возвращать аргумент, используемый оператором with, но для декораторов функций такой аналогии нет.
В приведённом выше примере нет чистого способа для менеджера контекста track_entry_and_exit вернуть экземпляр логгера для использования в теле вложенных операторов.
(Предложено Майклом Фордом в выпуске 9110.)
decimal and fractions¶
Марк Дикинсон разработал элегантную и эффективную схему, гарантирующую, что разные числовые типы данных будут иметь одинаковое хэш-значение всякий раз, когда их фактические значения равны (выпуск 8188):
assert hash(Fraction(3, 2)) == hash(1.5) == \
hash(Decimal("1.5")) == hash(complex(1.5, 0))
Некоторые детали хэширования раскрываются через новый атрибут sys.hash_info, который описывает разрядность хэш-значения, простой модуль, хэш-значения для бесконечности и nan, а также множитель, используемый для мнимой части числа:
>>> sys.hash_info
sys.hash_info(width=64, modulus=2305843009213693951, inf=314159, nan=0, imag=1000003)
Раннее решение ограничить совместимость различных числовых типов было смягчено. По-прежнему не поддерживается (и не рекомендуется) неявное смешивание в арифметических выражениях, таких как Decimal('1.1') + float('1.1'), поскольку последнее теряет информацию в процессе построения двоичного числа с плавающей точкой. Однако, поскольку существующее значение с плавающей точкой может быть без потерь преобразовано в десятичное или рациональное представление, имеет смысл добавить их в конструктор и поддерживать сравнения смешанных типов.
- Конструктор decimal.Decimal теперь принимает объекты float напрямую, поэтому больше нет необходимости использовать метод from_float() (выпуск 8257).
- Сравнения смешанных типов теперь полностью поддерживаются, так что объекты Decimal можно напрямую сравнивать с float и fractions.Fraction (выпуск 2531 и выпуск 8188).
Аналогичные изменения были внесены в fractions.Fraction, поэтому методы from_float() и from_decimal() больше не нужны (issue 8294):
>>> Decimal(1.1)
Decimal('1.100000000000000088817841970012523233890533447265625')
>>> Fraction(1.1)
Fraction(2476979795053773, 2251799813685248)
Ещё одно полезное изменение для модуля decimal заключается в том, что атрибут Context.clamp теперь стал общедоступным. Это полезно для создания контекстов, соответствующих форматам обмена десятичными числами, определённым в IEEE 754 (см. issue 8540).
(Авторы: Mark Dickinson и Raymond Hettinger.)
ftp¶
Класс ftplib.FTP теперь поддерживает протокол контекстного менеджера, чтобы безусловно перехватывать исключения socket.error и закрывать FTP соединение по завершении:
>>> from ftplib import FTP
>>> with FTP("ftp1.at.proftpd.org") as ftp:
ftp.login()
ftp.dir()
'230 Anonymous login ok, restrictions apply.'
dr-xr-xr-x 9 ftp ftp 154 May 6 10:43 .
dr-xr-xr-x 9 ftp ftp 154 May 6 10:43 ..
dr-xr-xr-x 5 ftp ftp 4096 May 6 10:43 CentOS
dr-xr-xr-x 3 ftp ftp 18 Jul 10 2008 Fedora
Other file-like objects such as mmap.mmap and fileinput.input() also grew auto-closing context managers:
with fileinput.input(files=('log1.txt', 'log2.txt')) as f:
for line in f:
process(line)
(Авторы: Tarek Ziadé и Giampaolo Rodolà (issue 4972), а также Georg Brandl (issue 8046, issue 1286).)
Класс FTP_TLS теперь принимает параметр context, который является объектом ssl.SSLContext, позволяющим объединять параметры конфигурации SSL, сертификаты и закрытые ключи в единую (потенциально долгоживущую) структуру.
(Автор: Giampaolo Rodolà; issue 8806.)
popen¶
Функции os.popen() и subprocess.Popen() теперь поддерживают инструкции with для автоматического закрытия файловых дескрипторов.
(Авторы: Antoine Pitrou и Brian Curtin в issue 7461 и issue 10554.)
select¶
Модуль select теперь предоставляет новый постоянный атрибут PIPE_BUF, который указывает минимальное количество байтов, гарантированно не вызывающих блокировку, когда select.select() сообщает, что канал готов к записи.
>>> import select
>>> select.PIPE_BUF
512
(Доступно в Unix-системах. Патч от Sébastien Sablé в issue 9862)
gzip и zipfile¶gzip and zipfile
gzip.GzipFile теперь реализует io.BufferedIOBase абстрактный базовый класс (за исключением truncate()). Он также имеет метод peek() и поддерживает непозиционируемые и дополненные нулями файловые объекты.
Модуль gzip также обзавёлся функциями compress() и decompress() для более удобного сжатия и распаковки в памяти. Имейте в виду, что текст должен быть закодирован как bytes перед сжатием и распаковкой:
>>> s = 'Three shall be the number thou shalt count, '
>>> s += 'and the number of the counting shall be three'
>>> b = s.encode() # преобразовать в utf-8
>>> len(b)
89
>>> c = gzip.compress(b)
>>> len(c)
77
>>> gzip.decompress(c).decode()[:42] # распаковать и преобразовать в текст
'Three shall be the number thou shalt count,'
(Авторы: Anand B. Pillai (issue 3488); а также Antoine Pitrou, Nir Aides и Brian Curtin (issue 9962, issue 1675951, issue 7471, issue 2846).)
Кроме того, класс zipfile.ZipExtFile был переработан для представления файлов, хранящихся внутри архива. Новая реализация значительно быстрее и может быть обёрнута в объект io.BufferedReader для дополнительного ускорения. Она также решает проблему, при которой перемежающиеся вызовы read и readline давали неверные результаты.
(Патч предоставлен Nir Aides в issue 7610.)
tarfile¶
Класс TarFile теперь можно использовать как менеджер контекста. Кроме того, его метод add() получил новую опцию filter, которая управляет тем, какие файлы добавляются в архив, и позволяет редактировать метаданные файлов.
Новая опция filter заменяет старый, менее гибкий параметр exclude, который теперь считается устаревшим. Если указан, необязательный параметр filter должен быть именованным аргументом. Предоставленная пользователем функция фильтрации принимает объект TarInfo и возвращает обновлённый объект TarInfo; если файл нужно исключить, функция может вернуть None:
>>> import tarfile, glob
>>> def myfilter(tarinfo):
if tarinfo.isfile(): # only save real files
tarinfo.uname = 'monty' # redact the user name
return tarinfo
>>> with tarfile.open(name='myarchive.tar.gz', mode='w:gz') as tf:
for filename in glob.glob('*.txt'):
tf.add(filename, filter=myfilter)
tf.list()
-rw-r--r-- monty/501 902 2011-01-26 17:59:11 annotations.txt
-rw-r--r-- monty/501 123 2011-01-26 17:59:11 general_questions.txt
-rw-r--r-- monty/501 3514 2011-01-26 17:59:11 prion.txt
-rw-r--r-- monty/501 124 2011-01-26 17:59:11 py_todo.txt
-rw-r--r-- monty/501 1399 2011-01-26 17:59:11 semaphore_notes.txt
(Предложено Tarek Ziadé, реализовано Lars Gustäbel в issue 6856.)
hashlib¶
Модуль hashlib имеет два новых постоянных атрибута, перечисляющих алгоритмы хеширования, которые гарантированно присутствуют во всех реализациях, и те, что доступны в текущей реализации:
>>> import hashlib
>>> hashlib.algorithms_guaranteed
{'sha1', 'sha224', 'sha384', 'sha256', 'sha512', 'md5'}
>>> hashlib.algorithms_available
{'md2', 'SHA256', 'SHA512', 'dsaWithSHA', 'mdc2', 'SHA224', 'MD4', 'sha256',
'sha512', 'ripemd160', 'SHA1', 'MDC2', 'SHA', 'SHA384', 'MD2',
'ecdsa-with-SHA1','md4', 'md5', 'sha1', 'DSA-SHA', 'sha224',
'dsaEncryption', 'DSA', 'RIPEMD160', 'sha', 'MD5', 'sha384'}
(Предложено Carl Chenet в issue 7418.)
ast¶
Модуль ast содержит замечательный универсальный инструмент для безопасного вычисления строк выражений с использованием синтаксиса литералов Python. Функция ast.literal_eval() служит безопасной альтернативой встроенной функции eval(), которой легко злоупотребить. Python 3.2 добавляет литералы bytes и set в список поддерживаемых типов: строки, байты, числа, кортежи, списки, словари, множества, булевы значения и None.
>>> from ast import literal_eval
>>> request = "{'req': 3, 'func': 'pow', 'args': (2, 0.5)}"
>>> literal_eval(request)
{'args': (2, 0.5), 'req': 3, 'func': 'pow'}
>>> request = "os.system('do something harmful')"
>>> literal_eval(request)
Traceback (most recent call last):
...
ValueError: malformed node or string: <_ast.Call object at 0x101739a10>
(Реализовано Бенджамином Петерсоном и Георгом Брандлем.)
os¶
В разных операционных системах используются различные кодировки для имён файлов и переменных окружения. Модуль os предоставляет две новые функции, fsencode() и fsdecode(), для кодирования и декодирования имён файлов:
>>> filename = 'Sehenswürdigkeiten'
>>> os.fsencode(filename)
b'Sehensw\xc3\xbcrdigkeiten'
Некоторые операционные системы разрешают прямой доступ к закодированным байтам в окружении. В таком случае константа os.supports_bytes_environ будет равна true.
For direct access to encoded environment variables (if available), use the new os.getenvb() function or use os.environb which is a bytes version of os.environ.
(Автор: Victor Stinner.)
shutil¶
Функция shutil.copytree() получила две новые опции:
- ignore_dangling_symlinks: когда symlinks=False, функция копирует файл, на который указывает символическая ссылка, а не саму ссылку. Эта опция подавляет ошибку, возникающую, если файл не существует.
- copy_function: вызываемый объект, который будет использоваться для копирования файлов. По умолчанию используется shutil.copy2().
(Автор: Tarek Ziadé.)
Кроме того, модуль shutil теперь поддерживает операции архивирования для файлов ZIP, несжатых файлов TAR, а также файлов TAR, сжатых с помощью gzip и bzip2. Также есть функции для регистрации дополнительных форматов архивов (например, файлов TAR, сжатых с помощью xz, или пользовательских форматов).
Основными функциями являются make_archive() и unpack_archive(). По умолчанию обе работают с текущим каталогом (который можно задать с помощью os.chdir()) и со всеми подкаталогами. Имя файла архива должно быть указано с полным путём. Операция архивирования не является разрушительной (исходные файлы остаются без изменений).
>>> import shutil, pprint
>>> os.chdir('mydata') # перейти в каталог исходного кода
>>> f = shutil.make_archive('/var/backup/mydata',
'zip') # archive the current directory
>>> f # показать имя архива
'/var/backup/mydata.zip'
>>> os.chdir('tmp') # перейти к распаковке
>>> shutil.unpack_archive('/var/backup/mydata.zip') # восстановить данные
>>> pprint.pprint(shutil.get_archive_formats()) # отобразить известные форматы
[('bztar', "bzip2'ed tar-file"),
('gztar', "gzip'ed tar-file"),
('tar', 'uncompressed tar file'),
('zip', 'ZIP file')]
>>> shutil.register_archive_format( # зарегистрировать новый формат архива
name = 'xz',
function = xz.compress, # callable archiving function
extra_args = [('level', 8)], # arguments to the function
description = 'xz compression'
)
(Автор: Tarek Ziadé.)
sqlite3¶
Модуль sqlite3 был обновлён до версии pysqlite 2.6.0. У него появились две новые возможности.
- Атрибут sqlite3.Connection.in_transit равен true, если есть активная транзакция с незафиксированными изменениями.
- Методы sqlite3.Connection.enable_load_extension() и sqlite3.Connection.load_extension() позволяют загружать расширения SQLite из файлов ”.so”. Одно из известных расширений – это расширение полнотекстового поиска, распространяемое вместе с SQLite.
(Авторы: R. David Murray и Shashwat Anand; issue 8845.)
html¶
Был добавлен новый модуль html с единственной функцией escape(), которая используется для экранирования зарезервированных символов в HTML-разметке:
>>> import html
>>> html.escape('x > 2 && x < 7')
'x > 2 && x < 7'
socket¶
В модуле socket появилось два улучшения.
- У объектов сокетов теперь есть метод detach(), который переводит сокет в закрытое состояние без фактического закрытия нижележащего файлового дескриптора. Последний затем можно использовать повторно для других целей. (Добавлено Antoine Pitrou; issue 8524.)
- socket.create_connection() теперь поддерживает протокол контекстного менеджера, чтобы безусловно перехватывать исключения socket.error и закрывать сокет по завершении. (Автор: Giampaolo Rodolà; issue 9794.)
ssl¶
Модуль ssl добавил ряд возможностей для удовлетворения общих требований безопасных (шифрованных, аутентифицированных) интернет-соединений:
- Новый класс SSLContext служит контейнером для постоянных данных SSL, таких как настройки протокола, сертификаты, закрытые ключи и различные другие параметры. Он включает метод wrap_socket() для создания SSL-сокета из SSL-контекста.
- Новая функция ssl.match_hostname() поддерживает проверку подлинности сервера для протоколов более высокого уровня, реализуя правила HTTPS (из RFC 2818), которые также подходят для других протоколов.
- Функция-конструктор ssl.wrap_socket() теперь принимает аргумент ciphers. Строка ciphers перечисляет разрешённые алгоритмы шифрования в формате, описанном в документации OpenSSL.
- При сборке с новыми версиями OpenSSL модуль ssl теперь поддерживает расширение Server Name Indication протокола TLS, позволяющее использовать несколько «виртуальных хостов» с разными сертификатами на одном IP-порту. Это расширение поддерживается только в режиме клиента и активируется передачей аргумента server_hostname в ssl.SSLContext.wrap_socket().
- В модуль ssl были добавлены различные параметры, такие как OP_NO_SSLv2, который отключает небезопасный и устаревший протокол SSLv2.
- Расширение теперь загружает все шифры и алгоритмы дайджестов OpenSSL. Если некоторые SSL-сертификаты не удаётся проверить, они сообщаются как ошибка «неизвестный алгоритм».
- Версию используемой OpenSSL теперь можно получить через атрибуты модуля ssl.OPENSSL_VERSION (строка), ssl.OPENSSL_VERSION_INFO (кортеж из 5 элементов) и ssl.OPENSSL_VERSION_NUMBER (целое число).
(Автор: Antoine Pitrou; issue 8850, issue 1589, issue 8322, issue 5639, issue 4870, issue 8484 и issue 8321.)
nntp¶
Модуль nntplib получил переработанную реализацию с улучшенной семантикой байтов и текста, а также более практичными API. Эти улучшения нарушают совместимость с версией nntplib в Python 3.1, которая сама по себе была частично неработоспособной.
Также была добавлена поддержка безопасных соединений как через неявный (с помощью nntplib.NNTP_SSL), так и явный (с помощью nntplib.NNTP.starttls()) TLS.
(Авторы: Antoine Pitrou (issue 9360) и Andrew Vant (issue 1926).)
сертификаты¶certificates
http.client.HTTPSConnection, urllib.request.HTTPSHandler и urllib.request.urlopen() теперь принимают необязательные аргументы для проверки сертификата сервера относительно набора центров сертификации, как рекомендуется при публичном использовании HTTPS.
(Добавлено Antoine Pitrou, issue 9003.)
imaplib¶
Поддержка явного TLS для стандартных IMAP4-соединений была добавлена через новый метод imaplib.IMAP4.starttls.
(Авторы: Lorenzo M. Catucci и Antoine Pitrou, issue 4471.)
http.client¶
В модуле http.client был сделан ряд небольших улучшений API. Устаревшие простые ответы HTTP 0.9 больше не поддерживаются, а параметр strict объявлен устаревшим во всех классах.
Классы HTTPConnection и HTTPSConnection теперь имеют параметр source_address, представляющий собой кортеж (host, port), указывающий, откуда устанавливается HTTP-соединение.
Добавлена поддержка проверки сертификатов и виртуальных хостов HTTPS в HTTPSConnection.
Метод request() у объектов соединения принимал необязательный аргумент body, чтобы можно было использовать файловый объект для передачи содержимого запроса. Теперь же аргумент body также принимает итерируемый объект, при условии, что он содержит явный заголовок Content-Length. Этот расширенный интерфейс стал гораздо более гибким.
Для установки HTTPS-соединения через прокси-сервер появился новый метод set_tunnel(), который задаёт хост и порт для туннелирования HTTP Connect.
Для соответствия поведению http.server библиотека HTTP-клиента теперь также кодирует заголовки в кодировке ISO-8859-1 (Latin-1). Для входящих заголовков она уже это делала, так что теперь поведение согласовано для входящего и исходящего трафика. (См. работу Armin Ronacher в issue 10980.)
unittest¶
Модуль unittest получил ряд улучшений: поддержка обнаружения тестов для пакетов, более простое экспериментирование в интерактивной оболочке, новые методы тестовых случаев, улучшенные диагностические сообщения при сбоях тестов и более понятные имена методов.
Вызов из командной строки python -m unittest теперь может принимать пути к файлам вместо имён модулей для запуска конкретных тестов (issue 10620). Новая система обнаружения тестов может находить тесты внутри пакетов, находя любой тест, импортируемый из корневой директории. Корневая директория может быть задана опцией -t, шаблон для сопоставления файлов – с помощью -p, а директория для начала поиска – с помощью -s:
$ python -m unittest discover -s my_proj_dir -p _test.py
(Предложено Michael Foord.)
Экспериментировать в интерактивной оболочке стало проще, поскольку класс unittest.case.TestCase теперь можно создавать без аргументов:
>>> TestCase().assertEqual(pow(2, 3), 8)
(Предложено Michael Foord.)
В модуле unittest появились два новых метода: assertWarns() и assertWarnsRegex(), которые проверяют, что заданный тип предупреждения вызывается тестируемым кодом:
with self.assertWarns(DeprecationWarning): legacy_function('XYZ')
(Автор: Antoine Pitrou, issue 9754.)
Ещё один новый метод, assertCountEqual(), используется для сравнения двух итерируемых объектов, чтобы определить, равны ли количества их элементов (то есть одинаковые ли элементы присутствуют с одинаковым числом вхождений, независимо от порядка):
def test_anagram(self): self.assertCountEqual('algorithm', 'logarithm')
(Автор: Raymond Hettinger.)
Одной из ключевых особенностей модуля unittest является стремление выдавать информативную диагностику при сбое теста. Когда это возможно, сбой записывается вместе с diff (разницей) вывода. Это особенно полезно при анализе логов неудачных тестовых запусков. Однако, поскольку diff'ы могут быть объёмными, появился новый атрибут maxDiff, который задаёт максимальную длину отображаемых diff'ов.
Кроме того, имена методов в модуле были приведены в порядок.
Например, assertRegex() – это новое имя для assertRegexpMatches(), которое было названо неправильно, потому что тест использует re.search(), а не re.match(). Другие методы, использующие регулярные выражения, теперь названы с краткой формой «Regex» вместо «Regexp» – это соответствует именам в других реализациях unittest, совпадает со старым названием модуля re в Python и имеет однозначное верблюжье написание.
(Предложено Raymond Hettinger; реализовано Ezio Melotti.)
Чтобы повысить согласованность, некоторые давно существующие псевдонимы методов объявляются устаревшими; вместо них следует использовать предпочтительные имена:
Старое имя
Предпочтительное имя
assert_()
assertEquals()
assertNotEquals()
assertAlmostEquals()
assertNotAlmostEquals()
Аналогично, методы TestCase.fail*, устаревшие в Python 3.1, как ожидается, будут удалены в Python 3.3. См. также раздел Deprecated aliases в документации unittest.
(Автор: Ezio Melotti; issue 9424.)
Метод assertDictContainsSubset() был объявлен устаревшим, поскольку он был реализован с ошибкой: аргументы передавались в неправильном порядке. Это создавало трудноуловимые иллюзии, когда тесты вида TestCase().assertDictContainsSubset({'a':1, 'b':2}, {'a':1}) завершались неудачей.
(Автор: Raymond Hettinger.)
random¶
Целочисленные методы модуля random теперь лучше обеспечивают равномерное распределение. Ранее они вычисляли выборки с помощью int(n*random()), что давало небольшое смещение, когда n не являлось степенью двойки. Теперь несколько выборок делаются из диапазона до следующей степени двойки, и выборка сохраняется только в том случае, если она попадает в диапазон 0 <= x < n. Затронутые функции и методы: randrange(), randint(), choice(), shuffle() и sample().
(Автор: Raymond Hettinger; issue 9025.)
poplib¶
Класс POP3_SSL теперь принимает параметр context, который является объектом ssl.SSLContext, позволяющим объединять параметры конфигурации SSL, сертификаты и закрытые ключи в одну (потенциально долгоживущую) структуру.
(Автор: Giampaolo Rodolà; issue 8807.)
asyncore¶
asyncore.dispatcher теперь предоставляет метод handle_accepted(), возвращающий пару (sock, addr). Этот метод вызывается при фактическом установлении соединения с новым удалённым узлом. Он предназначен для замены устаревшего метода handle_accept() и избавляет пользователя от необходимости напрямую вызывать accept().
(Автор: Giampaolo Rodolà; issue 6706.)
tempfile¶
Модуль tempfile получил новый контекстный менеджер TemporaryDirectory, обеспечивающий простое и детерминированное удаление временных каталогов:
with tempfile.TemporaryDirectory() as tmpdirname:
print('created temporary dir:', tmpdirname)
(Авторы: Neil Schemenauer и Nick Coghlan; issue 5178.)
inspect¶
Модуль inspect содержит новую функцию getgeneratorstate() для простого определения текущего состояния генератора-итератора:
>>> from inspect import getgeneratorstate >>> def gen(): yield 'demo' >>> g = gen() >>> getgeneratorstate(g) 'GEN_CREATED' >>> next(g) 'demo' >>> getgeneratorstate(g) 'GEN_SUSPENDED' >>> next(g, None) >>> getgeneratorstate(g) 'GEN_CLOSED'
(Авторы: Rodolpho Eckhardt и Nick Coghlan, issue 10220.)
Для поддержки поиска без возможности активации динамического атрибута модуль inspect содержит новую функцию getattr_static(). В отличие от hasattr(), это настоящий поиск только для чтения, который гарантированно не изменяет состояние во время поиска:
>>> class A: @property def f(self): print('Running') return 10 >>> a = A() >>> getattr(a, 'f') Running 10 >>> inspect.getattr_static(a, 'f') <property object at 0x1022bd788>
(Предложено Michael Foord.)
pydoc¶
Модуль pydoc теперь предоставляет значительно улучшенный интерфейс веб-сервера, а также новый параметр командной строки -b для автоматического открытия окна браузера для отображения этого сервера:
$ pydoc3.2 -b
(Автор: Ron Adam; issue 2001.)
dis¶
Модуль dis получил две новые функции для инспекции кода: code_info() и show_code(). Обе предоставляют подробную информацию об объекте кода для переданной функции, метода, строки исходного кода или объекта кода. Первая возвращает строку, вторая выводит её:
>>> import dis, random
>>> dis.show_code(random.choice)
Name: choice
Filename: /Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/random.py
Argument count: 2
Kw-only arguments: 0
Number of locals: 3
Stack size: 11
Flags: OPTIMIZED, NEWLOCALS, NOFREE
Constants:
0: 'Choose a random element from a non-empty sequence.'
1: 'Cannot choose from an empty sequence'
Names:
0: _randbelow
1: len
2: ValueError
3: IndexError
Variable names:
0: self
1: seq
2: i
Кроме того, функция dis() теперь принимает строковые аргументы, так что распространённую идиому dis(compile(s, '', 'eval')) можно сократить до dis(s):
>>> dis('3*x+1 if x%2==1 else x//2')
1 0 LOAD_NAME 0 (x)
3 LOAD_CONST 0 (2)
6 BINARY_MODULO
7 LOAD_CONST 1 (1)
10 COMPARE_OP 2 (==)
13 POP_JUMP_IF_FALSE 28
16 LOAD_CONST 2 (3)
19 LOAD_NAME 0 (x)
22 BINARY_MULTIPLY
23 LOAD_CONST 1 (1)
26 BINARY_ADD
27 RETURN_VALUE
>> 28 LOAD_NAME 0 (x)
31 LOAD_CONST 0 (2)
34 BINARY_FLOOR_DIVIDE
35 RETURN_VALUE
В совокупности эти улучшения упрощают изучение того, как реализован CPython, и позволяют самому увидеть, что делает синтаксис языка «под капотом».
(Автор: Nick Coghlan, issue 9147.)
dbm¶
Все модули баз данных теперь поддерживают методы get() и setdefault().
(Предложено Ray Allen в issue 9523.)
ctypes¶
Новый тип ctypes.c_ssize_t представляет тип данных C ssize_t.
site¶
Модуль site содержит три новые функции для вывода подробной информации об установке Python.
- getsitepackages() выводит список всех глобальных каталогов site-packages.
- getuserbase() сообщает базовый каталог пользователя, в котором могут храниться данные.
- getusersitepackages() показывает путь к каталогу site-packages для текущего пользователя.
>>> import site
>>> site.getsitepackages()
['/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/site-packages',
'/Library/Frameworks/Python.framework/Versions/3.2/lib/site-python',
'/Library/Python/3.2/site-packages']
>>> site.getuserbase()
'/Users/raymondhettinger/Library/Python/3.2'
>>> site.getusersitepackages()
'/Users/raymondhettinger/Library/Python/3.2/lib/python/site-packages'
Удобно, что часть функциональности site доступна напрямую из командной строки:
$ python -m site --user-base
/Users/raymondhettinger/.local
$ python -m site --user-site
/Users/raymondhettinger/.local/lib/python3.2/site-packages
(Автор: Tarek Ziadé, issue 6693.)
sysconfig¶
Новый модуль sysconfig упрощает поиск путей установки и переменных конфигурации, которые различаются между платформами и установками.
Модуль предоставляет простые функции доступа для получения информации о платформе и версии:
- get_platform() возвращает такие значения, как linux-i586 или macosx-10.6-ppc.
- get_python_version() возвращает строку версии Python, например «3.2».
Он также предоставляет доступ к путям и переменным, соответствующим одной из семи именованных схем, используемых distutils. К ним относятся posix_prefix, posix_home, posix_user, nt, nt_user, os2, os2_home:
- get_paths() создаёт словарь, содержащий пути установки для текущей схемы установки.
- get_config_vars() возвращает словарь переменных, зависящих от платформы.
Также имеется удобный интерфейс командной строки:
C:\Python32>python -m sysconfig
Platform: "win32"
Python version: "3.2"
Current installation scheme: "nt"
Paths:
data = "C:\Python32"
include = "C:\Python32\Include"
platinclude = "C:\Python32\Include"
platlib = "C:\Python32\Lib\site-packages"
platstdlib = "C:\Python32\Lib"
purelib = "C:\Python32\Lib\site-packages"
scripts = "C:\Python32\Scripts"
stdlib = "C:\Python32\Lib"
Variables:
BINDIR = "C:\Python32"
BINLIBDEST = "C:\Python32\Lib"
EXE = ".exe"
INCLUDEPY = "C:\Python32\Include"
LIBDEST = "C:\Python32\Lib"
SO = ".pyd"
VERSION = "32"
abiflags = ""
base = "C:\Python32"
exec_prefix = "C:\Python32"
platbase = "C:\Python32"
prefix = "C:\Python32"
projectbase = "C:\Python32"
py_version = "3.2"
py_version_nodot = "32"
py_version_short = "3.2"
srcdir = "C:\Python32"
userbase = "C:\Documents and Settings\Raymond\Application Data\Python"
(Перенесено из Distutils Тареком Зиаде.)
pdb¶
Модуль отладчика pdb получил ряд улучшений удобства использования:
- pdb.py теперь имеет опцию -c, которая выполняет команды, заданные в файле сценария .pdbrc.
- Файл сценария .pdbrc может содержать команды continue и next, которые продолжают отладку.
- Конструктор класса Pdb теперь принимает аргумент nosigint.
- Новые команды: l(list), ll(long list) и source для просмотра исходного кода.
- Новые команды: display и undisplay для отображения или скрытия значения выражения, если оно изменилось.
- Новая команда: interact для запуска интерактивного интерпретатора, содержащего глобальные и локальные имена, найденные в текущей области видимости.
- Точки останова можно удалять по номеру.
(Добавлено Георгом Брандлем, Антонио Куни и Ильёй Сандлером.)
configparser¶
Модуль configparser был изменён для улучшения удобства использования и предсказуемости парсера по умолчанию и поддерживаемого им синтаксиса INI. Старый класс ConfigParser был удалён в пользу SafeConfigParser, который, в свою очередь, был переименован в ConfigParser. Поддержка строчных комментариев теперь отключена по умолчанию, а дублирование разделов или опций не допускается в одном источнике конфигурации.
Парсеры конфигураций получили новый API на основе протокола отображения:
>>> parser = ConfigParser()
>>> parser.read_string("""
[DEFAULT]
location = upper left
visible = yes
editable = no
color = blue
[main]
title = Main Menu
color = green
[options]
title = Options
""")
>>> parser['main']['color']
'green'
>>> parser['main']['editable']
'no'
>>> section = parser['options']
>>> section['title']
'Options'
>>> section['title'] = 'Options (editable: %(editable)s)'
>>> section['title']
'Options (editable: no)'
Новый API реализован поверх классического API, поэтому пользовательские подклассы парсеров должны иметь возможность использовать его без изменений.
Структура INI-файла, принимаемая парсерами конфигураций, теперь может быть настроена. Пользователи могут задавать альтернативные разделители опция/значение и префиксы комментариев, изменять имя секции DEFAULT или переключать синтаксис интерполяции.
Реализована поддержка подключаемой интерполяции, включая дополнительный обработчик интерполяции ExtendedInterpolation:
>>> parser = ConfigParser(interpolation=ExtendedInterpolation())
>>> parser.read_dict({'buildout': {'directory': '/home/ambv/zope9'},
'custom': {'prefix': '/usr/local'}})
>>> parser.read_string("""
[buildout]
parts =
zope9
instance
find-links =
${buildout:directory}/downloads/dist
[zope9]
recipe = plone.recipe.zope9install
location = /opt/zope
[instance]
recipe = plone.recipe.zope9instance
zope9-location = ${zope9:location}
zope-conf = ${custom:prefix}/etc/zope.conf
""")
>>> parser['buildout']['find-links']
'\n/home/ambv/zope9/downloads/dist'
>>> parser['instance']['zope-conf']
'/usr/local/etc/zope.conf'
>>> instance = parser['instance']
>>> instance['zope-conf']
'/usr/local/etc/zope.conf'
>>> instance['zope9-location']
'/opt/zope'
Был также введён ряд небольших возможностей, таких как поддержка указания кодировки в операциях чтения, указание значений по умолчанию для get-функций или чтение напрямую из словарей и строк.
(Все изменения предоставлены Łukasz Langa.)
urllib.parse¶
Для модуля urllib.parse был внесён ряд улучшений удобства использования.
Функция urlparse() теперь поддерживает адреса IPv6, как описано в RFC 2732:
>>> import urllib.parse
>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/')
ParseResult(scheme='http',
netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]',
path='/foo/',
params='',
query='',
fragment='')
Функция urldefrag() теперь возвращает именованный кортеж:
>>> r = urllib.parse.urldefrag('http://python.org/about/#target')
>>> r
DefragResult(url='http://python.org/about/', fragment='target')
>>> r[0]
'http://python.org/about/'
>>> r.fragment
'target'
Кроме того, функция urlencode() теперь стала гораздо более гибкой: она принимает аргумент query как строку, так и тип bytes. Если это строка, то параметры safe, encoding и error передаются в quote_plus() для кодирования:
>>> urllib.parse.urlencode([
('type', 'telenovela'),
('name', '¿Dónde Está Elisa?')],
encoding='latin-1')
'type=telenovela&name=%BFD%F3nde+Est%E1+Elisa%3F'
Как подробно описано в Parsing ASCII Encoded Bytes, все функции urllib.parse теперь принимают на вход ASCII-закодированные байтовые строки, при условии, что они не смешиваются с обычными строками. Если в качестве параметров заданы ASCII-закодированные байтовые строки, возвращаемые типы также будут ASCII-закодированными байтовыми строками:
>>> urllib.parse.urlparse(b'http://www.python.org:80/about/')
ParseResultBytes(scheme=b'http', netloc=b'www.python.org:80',
path=b'/about/', params=b'', query=b'', fragment=b'')
(Работа Ника Коглана, Дэна Мана и Сентила Кумарана в issue 2987, issue 5468 и issue 9873.)
mailbox¶
Благодаря согласованным усилиям Р. Дэвида Мюррея, модуль mailbox был исправлен для Python 3.2. Проблема заключалась в том, что mailbox изначально был спроектирован с текстовым интерфейсом, но email-сообщения лучше представлять через bytes, поскольку разные части сообщения могут иметь разные кодировки.
Решение задействовало двоичную поддержку пакета email для разбора произвольных email-сообщений. Кроме того, решение потребовало ряда изменений API.
Как и ожидалось, метод add() для объектов mailbox.Mailbox теперь принимает двоичный ввод.
StringIO и ввод из текстового файла устарели. Кроме того, строковый ввод будет завершаться ошибкой на раннем этапе, если используются символы не в ASCII. Ранее ошибка возникала при обработке письма на более позднем этапе.
Также добавлена поддержка двоичного вывода. Метод get_file() теперь возвращает файл в двоичном режиме (ранее он некорректно устанавливал текстовый режим). Кроме того, появился новый метод get_bytes(), который возвращает bytes-представление сообщения, соответствующее заданному key.
По-прежнему можно получить недвоичный вывод с помощью метода старого API get_string(), но такой подход не очень полезен. Вместо этого лучше извлекать сообщения из объекта Message или загружать их из двоичного ввода.
(Предоставлено Р. Дэвидом Мюрреем, при участии Штеффена Даоде Нурпмезо и начального патча от Виктора Стиннера в issue 9124.)
turtledemo¶
Демонстрационный код для модуля turtle был перемещён из каталога Demo в основную библиотеку. Он включает более десятка примеров сценариев с живыми отображениями. Находясь в sys.path, его теперь можно запускать напрямую из командной строки:
$ python -m turtledemo
(Перемещено из каталога Demo Александром Белопольским в issue 10199.)
Многопоточность¶Multi-threading
Механизм сериализации выполнения одновременно работающих потоков Python (обычно известный как GIL или Глобальная блокировка интерпретатора) был переписан. Среди целей были более предсказуемые интервалы переключения и снижение накладных расходов из-за конкуренции за блокировку и количества последующих системных вызовов. Понятие «интервал проверки» для разрешения переключения потоков было отброшено и заменено абсолютной длительностью, выраженной в секундах. Этот параметр настраивается через sys.setswitchinterval(). В настоящее время по умолчанию он равен 5 миллисекундам.
Дополнительные сведения о реализации можно прочитать в сообщении в списке рассылки python-dev (однако, «приоритетные запросы», как описано в этом сообщении, не были сохранены для включения).
(Предоставлено Antoine Pitrou.)
Обычные и рекурсивные блокировки теперь принимают необязательный аргумент timeout для своего метода acquire(). (Автор: Antoine Pitrou; issue 7316.)
Аналогично, метод threading.Semaphore.acquire() также получил аргумент timeout. (Автор: Torsten Landschoff; issue 850728.)
Теперь на платформах, использующих Pthreads, захват обычных и рекурсивных блокировок может быть прерван сигналами. Это означает, что программы Python, попавшие в взаимоблокировку при захвате блокировок, можно успешно завершить, многократно отправляя процессу сигнал SIGINT (нажатием Ctrl+C в большинстве оболочек). (Автор: Reid Kleckner; issue 8844.)
Оптимизации¶Optimizations
Добавлено несколько небольших улучшений производительности:
Оптимизатор peephole в Python теперь распознает такие шаблоны, как x in {1, 2, 3}, как проверку принадлежности множеству констант. Оптимизатор преобразует set в frozenset и сохраняет предварительно созданную константу.
Теперь, когда замедление устранено, стало практичным начать писать проверки принадлежности с использованием set-нотации. Этот стиль одновременно ясен семантически и быстр в работе:
extension = name.rpartition('.')[2] if extension in {'xml', 'html', 'xhtml', 'css'}: handle(name)
(Патч и дополнительные тесты предоставлены Dave Malcolm; issue 6690).
Сериализация и десериализация данных с помощью модуля pickle теперь выполняется в несколько раз быстрее.
(Авторы: Alexandre Vassalotti, Antoine Pitrou и команда Unladen Swallow; issue 9410 и issue 3873.)
Алгоритм Timsort, используемый в list.sort() и sorted(), теперь работает быстрее и использует меньше памяти при вызове с функцией ключа. Раньше каждый элемент списка оборачивался временным объектом, который запоминал значение ключа для каждого элемента. Теперь два массива – ключей и значений – сортируются параллельно. Это экономит память, занимаемую обёртками для сортировки, и время, затрачиваемое на делегирование сравнений.
(Патч от Daniel Stutzbach в issue 9915.)
Производительность декодирования JSON улучшена, а потребление памяти снижено, когда одна и та же строка повторяется для нескольких ключей. Кроме того, кодирование JSON теперь использует ускорения на C, когда аргумент sort_keys равен true.
(Авторы: Antoine Pitrou в issue 7451, и Raymond Hettinger с Antoine Pitrou в issue 10314.)
Рекурсивные блокировки (создаваемые через API threading.RLock()) теперь выигрывают от реализации на C, которая делает их такими же быстрыми, как обычные блокировки, и в 10–15 раз быстрее предыдущей реализации на чистом Python.
(Автор: Antoine Pitrou; issue 3001.)
Алгоритм быстрого поиска в stringlib теперь используется методами split(), splitlines() и replace() объектов bytes, bytearray и str. Кроме того, этот алгоритм также используется методами rfind(), rindex(), rsplit() и rpartition().
(Патч от Florent Xicluna в issue 7622 и issue 7462.)
Преобразования целых чисел в строки теперь работают с двумя «цифрами» за раз, сокращая количество операций деления и взятия остатка.
(issue 6713 от Gawain Bolton, Mark Dickinson и Victor Stinner.)
Было реализовано несколько других незначительных оптимизаций. Разность множеств теперь выполняется быстрее, когда один операнд намного больше другого (патч от Andress Bennetts в issue 8685). Метод array.repeat() получил более быструю реализацию (issue 1569291 от Alexander Belopolsky). Класс BaseHTTPRequestHandler имеет более эффективную буферизацию (issue 3709 от Andrew Schaaf). Функция operator.attrgetter() ускорена (issue 10160 от Christos Georgiou). А ConfigParser загружает многострочные аргументы немного быстрее (issue 7113 от Łukasz Langa).
Юникод¶Unicode
Python был обновлён до Unicode 6.0.0. Обновление стандарта добавляет более 2000 новых символов, включая эмодзи, которые важны для мобильных телефонов.
Кроме того, обновлённый стандарт изменил свойства символов для двух символов каннада (U+0CF1, U+0CF2) и одного числового символа New Tai Lue (U+19DA), сделав первые допустимыми для использования в идентификаторах, а последний – недопустимым. Подробнее см. Unicode Character Database Changes.
Кодеки¶Codecs
Добавлена поддержка арабской кодировки DOS cp720 (issue 1616979).
MBCS encoding no longer ignores the error handler argument. In the default strict mode, it raises an UnicodeDecodeError when it encounters an undecodable byte sequence and an UnicodeEncodeError for an unencodable character.
Кодек MBCS поддерживает обработчики ошибок 'strict' и 'ignore' для декодирования, и 'strict' и 'replace' для кодирования.
Для эмуляции кодировки MBCS из Python 3.1 выберите обработчик 'ignore' для декодирования и обработчик 'replace' для кодирования.
На Mac OS X Python декодирует аргументы командной строки с помощью 'utf-8', а не кодировки локали.
По умолчанию tarfile использует кодировку 'utf-8' в Windows (вместо 'mbcs') и обработчик ошибок 'surrogateescape' на всех операционных системах.
Документация¶Documentation
Документация продолжает улучшаться.
В верхней части длинных разделов, таких как Встроенные функции, теперь добавлена таблица быстрых ссылок. В случае itertools ссылки сопровождаются таблицами кратких сводок в стиле шпаргалки, чтобы дать обзор и освежить память без необходимости читать всю документацию.
В некоторых случаях исходный код на чистом Python может быть полезным дополнением к документации, поэтому теперь многие модули содержат быстрые ссылки на последнюю версию исходного кода. Например, документация модуля functools имеет вверху быструю ссылку с подписью:
Исходный код Lib/functools.py.
(Автор: Raymond Hettinger; см. обоснование.)
Документация теперь содержит больше примеров и рецептов. В частности, модуль re имеет обширный раздел Примеры регулярных выражений. Кроме того, модуль itertools продолжает обновляться новыми Рецептами itertools.
Модуль datetime теперь имеет вспомогательную реализацию на чистом Python. Функциональность не изменилась. Это просто предоставляет более удобную для чтения альтернативную реализацию.
(Автор: Alexander Belopolsky; issue 9528.)
Не поддерживаемая директория Demo удалена. Некоторые демонстрации были интегрированы в документацию, некоторые перемещены в директорию Tools/demo, а остальные полностью удалены.
(Автор: Georg Brandl; issue 7962.)
IDLE¶
Меню «Формат» теперь содержит опцию для очистки исходных файлов путём удаления замыкающих пробелов.
(Автор: Raymond Hettinger; issue 5150.)
IDLE на Mac OS X теперь работает как с Carbon AquaTk, так и с Cocoa AquaTk.
(Авторы: Kevin Walzer, Ned Deily и Ronald Oussoren; issue 6075.)
Репозиторий кода¶Code Repository
В дополнение к существующему репозиторию Subversion по адресу http://svn.python.org теперь также доступен репозиторий Mercurial по адресу http://hg.python.org/.
После выхода версии 3.2 планируется перейти на Mercurial в качестве основного репозитория. Эта распределённая система управления версиями должна упростить членам сообщества создание и обмен внешними наборами изменений. Подробнее см. PEP 385.
Чтобы освоить новую систему контроля версий, ознакомьтесь с учебником Джоэла Спольски или руководством по рабочим процессам Mercurial.
Изменения в сборке и C API¶Build and C API Changes
Изменения процесса сборки Python и C API включают:
Скрипты idle, pydoc и 2to3 теперь устанавливаются с суффиксом, зависящим от версии, при make altinstall (issue 10679).
C-функции, обращающиеся к базе данных Unicode, теперь принимают и возвращают символы из полного диапазона Unicode, даже в узких сборках Unicode (Py_UNICODE_TOLOWER, Py_UNICODE_ISDECIMAL и другие). Заметное отличие в Python: unicodedata.numeric() теперь возвращает правильное значение для больших кодовых точек, а repr() может считать больше символов печатаемыми.
(Сообщил Bupjoe Lee, исправил Amaury Forgeot D’Arc; issue 5127.)
Вычисляемые goto теперь включены по умолчанию в поддерживаемых компиляторах (которые определяются скриптом configure). Их можно выборочно отключить, указав --without-computed-gotos.
(Автор: Antoine Pitrou; issue 9203.)
Опция --with-wctype-functions была удалена. Теперь для всех функций используется встроенная база данных Unicode.
(Автор: Amaury Forgeot D’Arc; issue 9210.)
Хеш-значения теперь являются значениями нового типа Py_hash_t, который определяется как имеющий тот же размер, что и указатель. Ранее они были типа long, который в некоторых 64-битных операционных системах по-прежнему имеет длину всего 32 бита. В результате этого исправления set и dict теперь могут содержать более 2**32 элементов в сборках с 64-битными указателями (ранее они могли вырасти до такого размера, но их производительность катастрофически падала).
(Предложено Raymond Hettinger, реализовано Benjamin Peterson; issue 9778.)
Новый макрос Py_VA_COPY копирует состояние списка переменных аргументов. Он эквивалентен va_copy из C99, но доступен на всех платформах Python (issue 2443).
Новая функция C API PySys_SetArgvEx() позволяет встроенному интерпретатору задавать sys.argv без изменения sys.path (issue 5753).
PyEval_CallObject теперь доступен только в виде макроса. Объявление функции, которое сохранялось для обратной совместимости, теперь удалено – макрос был введён в 1997 году (issue 8276).
Появилась новая функция PyLong_AsLongLongAndOverflow(), аналогичная PyLong_AsLongAndOverflow(). Обе служат для преобразования Python int в нативный тип фиксированного размера с обнаружением случаев, когда преобразование невозможно (issue 7767).
Функция PyUnicode_CompareWithASCIIString() теперь возвращает не равно, если строка Python завершается NUL.
Появилась новая функция PyErr_NewExceptionWithDoc(), похожая на PyErr_NewException(), но позволяющая указать docstring. Это даёт исключениям на C такие же возможности самодокументирования, как у их аналогов на чистом Python (issue 7033).
При сборке с опцией --with-valgrind аллокатор pymalloc будет автоматически отключаться при работе под Valgrind. Это обеспечивает улучшенное обнаружение утечек памяти при работе под Valgrind, одновременно используя преимущества pymalloc в остальное время (issue 2422).
Удалён формат O? из функций PyArg_Parse. Этот формат больше не используется и никогда не был документирован (issue 8837).
Было внесено множество других мелких изменений в C-API. Полный список см. в файле Misc/NEWS.
Кроме того, в сборку для Mac OS X был внесён ряд обновлений; подробности см. в Mac/BuildScript/README.txt. Для пользователей 32/64-битной сборки существует известная проблема с Tcl/Tk по умолчанию в Mac OS X 10.6. Поэтому рекомендуется установить обновлённую альтернативу, например ActiveState Tcl/Tk 8.5.9. Дополнительные сведения – на http://www.python.org/download/mac/tcltk/.
Переход на Python 3.2¶Porting to Python 3.2
В этом разделе перечислены описанные ранее изменения и другие исправления ошибок, которые могут потребовать доработки вашего кода:
Модуль configparser претерпел ряд улучшений. Основное изменение – замена старого класса ConfigParser на давно предпочтительную альтернативу SafeConfigParser. Кроме того, имеется ряд мелких несовместимостей:
- Синтаксис интерполяции теперь проверяется при операциях get() и set(). В схеме интерполяции по умолчанию допустимы только два токена со знаками процента: %(name)s и %%, причём последний представляет собой экранированный знак процента.
- Методы set() и add_section() теперь проверяют, что значения являются строками. Ранее неподдерживаемые типы могли быть случайно введены.
- Повторяющиеся разделы или параметры из одного источника теперь вызывают DuplicateSectionError или DuplicateOptionError. Ранее дубликаты молча перезаписывали предыдущую запись.
- Встрочные комментарии теперь по умолчанию отключены, поэтому символ ; теперь можно безопасно использовать в значениях.
- Комментарии теперь можно располагать с отступом. Следовательно, чтобы ; или # оказались в начале строки в многострочных значениях, их нужно интерполировать. Это предотвращает ошибочную интерпретацию префиксных символов комментариев в значениях как комментариев.
- "" теперь является допустимым значением и больше не преобразуется автоматически в пустую строку. Для пустых строк используйте "option =" в строке.
Модуль nntplib был существенно переработан, поэтому его API часто несовместимы с API версии 3.1.
Объекты bytearray больше нельзя использовать в качестве имён файлов; вместо этого их следует преобразовывать в bytes.
Методы array.tostring() и array.fromstring() были переименованы в array.tobytes() и array.frombytes() для ясности. Старые имена объявлены устаревшими. (См. issue 8990.)
Функции PyArg_Parse*():
- Формат «t#» удалён: используйте «s#» или «s*»
- Форматы «w» и «w#» удалены: используйте «w*»
Тип PyCObject, устаревший в 3.1, был удалён. Для обёртывания непрозрачных C-указателей в объекты Python следует использовать API PyCapsule; новый тип имеет чётко определённый интерфейс для передачи информации о типобезопасности и менее сложную сигнатуру для вызова деструктора.
Функция sys.setfilesystemencoding() была удалена из-за ошибочного дизайна.
Функция и метод random.seed() теперь «солят» строковые начальные значения с помощью хеш-функции sha512. Чтобы получить доступ к предыдущей версии seed для воспроизведения последовательностей Python 3.1, установите аргумент version в 1, random.seed(s, version=1).
Ранее устаревшая функция string.maketrans() была удалена в пользу статических методов bytes.maketrans() и bytearray.maketrans(). Это изменение устраняет путаницу относительно того, какие типы поддерживались модулем string. Теперь str, bytes и bytearray имеют собственные методы maketrans и translate с промежуточными таблицами перевода соответствующего типа.
(Автор: Georg Brandl; issue 5675.)
Ранее устаревшая функция contextlib.nested() была удалена в пользу обычного оператора with, который может принимать несколько менеджеров контекста. Последний подход быстрее (поскольку является встроенным) и лучше завершает работу нескольких менеджеров контекста, когда один из них вызывает исключение:
with open('mylog.txt') as infile, open('a.out', 'w') as outfile: for line in infile: if '<critical>' in line: outfile.write(line)
(Предложено Georg Brandl и Mattias Brändström; appspot issue 53094.)
struct.pack() теперь допускает только байты для строкового кода упаковки s. Ранее он принимал текстовые аргументы и неявно кодировал их в байты с помощью UTF-8. Это было проблематично, поскольку делались предположения о правильной кодировке и потому что кодировка с переменной длиной может дать сбой при записи в сегмент фиксированной длины структуры.
Код вида struct.pack('<6sHHBBB', 'GIF87a', x, y) следует переписать с использованием байтов вместо текста: struct.pack('<6sHHBBB', b'GIF87a', x, y).
(Обнаружено Дэвидом Бизли и исправлено Виктором Штиннером; issue 10783.)
Класс xml.etree.ElementTree теперь при ошибке разбора вызывает исключение xml.etree.ElementTree.ParseError. Ранее он вызывал xml.parsers.expat.ExpatError.
Новое, более длинное строковое представление str() чисел с плавающей запятой может нарушить doctest-ы, которые полагаются на старый формат вывода.
В subprocess.Popen значение по умолчанию для close_fds теперь равно True в Unix; в Windows оно равно True, если три стандартных потока установлены в None, и False в противном случае. Ранее close_fds всегда было False по умолчанию, что приводило к трудноуловимым ошибкам или состояниям гонки, когда открытые файловые дескрипторы просачивались в дочерний процесс.
Поддержка устаревшего HTTP 0.9 удалена из urllib.request и http.client. Такая поддержка всё ещё присутствует на стороне сервера (в http.server).
(Автор: Antoine Pitrou, issue 10711.)
SSL-сокеты в режиме тайм-аута теперь возбуждают socket.timeout при возникновении тайм-аута, а не общее исключение SSLError.
(Автор: Antoine Pitrou, issue 10272.)
Вводящие в заблуждение функции PyEval_AcquireLock() и PyEval_ReleaseLock() официально устарели. Вместо них следует использовать API, учитывающие состояние потоков (такие как PyEval_SaveThread() и PyEval_RestoreThread()).
Из-за рисков безопасности функция asyncore.handle_accept() устарела, и для её замены добавлена новая функция asyncore.handle_accepted().
(Автор: Giampaolo Rodola, issue 6706.)
Из-за новой реализации GIL PyEval_InitThreads() больше нельзя вызывать до Py_Initialize().