Что нового в Python 3.2

Автор:

Раймонд Хеттингер

В этой статье рассказывается о новых возможностях Python 3.2 по сравнению с 3.1. Python 3.2 был выпущен 20 февраля 2011 года. В статье рассматривается несколько основных моментов и приводится несколько примеров. Более подробную информацию вы найдете в файле Misc/NEWS.

См.также

PEP 392 - График выхода Python 3.2

PEP 384: Определение стабильного ABI

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

В Python 3.2 появился альтернативный подход: модули расширения, которые ограничивают себя ограниченным API (определяя Py_LIMITED_API), не могут использовать многие внутренние функции, но ограничиваются набором функций API, который обещает быть стабильным в течение нескольких релизов. Как следствие, модули расширения, созданные для 3.2 в таком режиме, будут работать и в 3.3, 3.4 и так далее. Модули расширения, использующие детали структур памяти, по-прежнему могут быть собраны, но их придется перекомпилировать для каждого релиза.

См.также

PEP 384 - Определение стабильного ABI

PEP написан Мартином фон Лёвисом.

PEP 389: Модуль разбора командной строки Argparse

Новый модуль для разбора командной строки, argparse, был введен, чтобы преодолеть ограничения optparse, который не обеспечивал поддержку позиционных аргументов (не только опций), подкоманд, обязательных опций и других распространенных схем указания и проверки опций.

Этот модуль уже получил широкое распространение в сообществе в качестве стороннего модуля. Будучи более функциональным, чем его предшественник, модуль argparse теперь является предпочтительным модулем для обработки командной строки. Старый модуль все еще остается доступным из-за значительного количества унаследованного кода, который зависит от него.

Вот аннотированный пример парсера, демонстрирующий такие возможности, как ограничение результатов набором вариантов, указание metavar в окне помощи, проверка наличия одного или нескольких позиционных аргументов, а также создание обязательной опции:

import argparse
parser = argparse.ArgumentParser(
            description = 'Manage servers',         # main description for help
            epilog = 'Tested on Solaris and Linux') # displayed after help
parser.add_argument('action',                       # argument name
            choices = ['deploy', 'start', 'stop'],  # three allowed values
            help = 'action on each target')         # help msg
parser.add_argument('targets',
            metavar = 'HOSTNAME',                   # var name used in help msg
            nargs = '+',                            # require one or more targets
            help = 'url for target machines')       # help msg explanation
parser.add_argument('-u', '--user',                 # -u or --user option
            required = True,                        # make it a required argument
            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: Конфигурация на основе словаря для ведения журнала

Модуль 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

Код для создания и управления параллелизмом собирается в новом пространстве имен верхнего уровня, concurrent. Его первым членом является пакет futures, который предоставляет унифицированный высокоуровневый интерфейс для управления потоками и процессами.

Дизайн concurrent.futures был вдохновлен пакетом java.util.concurrent. В этой модели выполняющийся вызов и его результат представлены объектом Future, который абстрагирует функции, общие для потоков, процессов и удаленных вызовов процедур. Этот объект поддерживает проверку состояния (выполняется или выполнено), таймауты, отмены, добавление обратных вызовов, а также доступ к результатам или исключениям.

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

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

Оба класса имеют общий интерфейс с тремя методами: submit() для планирования вызова и возврата объекта Future; map() для планирования множества асинхронных вызовов одновременно и shutdown() для освобождения ресурсов. Класс является context manager и может использоваться в операторе with, чтобы гарантировать автоматическое освобождение ресурсов после завершения выполнения текущих фьючерсов.

Простым примером 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, 'src3.txt', 'dest4.txt')

См.также

PEP 3148 - Фьючерсы - асинхронное выполнение вычислений

Автор сценария PEP - Брайан Куинлан.

Code for Threaded Parallel URL reads, пример использования потоков для параллельной выборки нескольких веб-страниц.

Code for computing prime numbers in parallel, пример демонстрирует ProcessPoolExecutor.

PEP 3147: Справочники репозиториев PYC

Схема 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 был обновлен новым abstract base classes для загрузки файлов байткода. Устаревшие ABC, PyLoader и PyPycLoader, были упразднены (инструкции о том, как сохранить совместимость с Python 3.1, включены в документацию).

См.также

PEP 3147 - Директории репозитория PYC

PEP написан Барри Варшавом.

PEP 3149: ABI-версия файлов .so с метками

Каталог репозитория PYC позволяет совместно размещать несколько файлов кэша байткода. Этот PEP реализует аналогичный механизм для общих объектных файлов, предоставляя им общий каталог и отдельные имена для каждой версии.

Общий каталог - «pyshared», а имена файлов отличаются друг от друга, указывая реализацию Python (например, CPython, PyPy, Jython и т. д.), мажорный и минорный номера версий, а также необязательные флаги сборки (например, «d» для debug, «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')       # find the version tag
'cpython-32mu'
>>> sysconfig.get_config_var('EXT_SUFFIX')  # find the full filename extension
'.cpython-32mu.so'

См.также

PEP 3149 - Версия ABI Отмеченные файлы .so

PEP написан Барри Варшавом.

PEP 3333: Интерфейс шлюза веб-сервера Python 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() и окружение должны использовать родные строки. Смешивать эти два вида нельзя.

Для реализаторов серверов, пишущих пути CGI-to-WSGI или другие протоколы в стиле CGI, пользователи должны иметь возможность обращаться к окружению с помощью родных строк, даже если базовая платформа может иметь другую конвенцию. Чтобы преодолеть этот разрыв, в модуле wsgiref появилась новая функция wsgiref.handlers.read_environ() для перекодирования CGI-переменных из os.environ в родные строки и возврата нового словаря.

См.также

PEP 3333 - Интерфейс шлюза веб-сервера Python v1.0.1

PEP написан Филиппом Эби.

Другие языковые изменения

Некоторые более мелкие изменения, внесенные в ядро языка Python:

  • Форматирование строк для format() и str.format() получило новые возможности для символа формата #. Ранее для целых чисел в двоичной, восьмеричной или шестнадцатеричной системе счисления он приводил к префиксу „0b“, „0o“ или „0x“ соответственно. Теперь он также может работать с плавающими, комплексными и десятичными числами, заставляя вывод всегда иметь десятичную точку, даже если за ней нет цифр.

    >>> format(20, '#o')
    '0o24'
    >>> format(12.34, '#5.0f')
    '  12.'
    

    (Предложено Марком Дикинсоном и реализовано Эриком Смитом в bpo-7094).

  • Также есть новый метод str.format_map(), который расширяет возможности существующего метода str.format(), принимая произвольные объекты mapping. Этот новый метод позволяет использовать форматирование строк с любым из множества словареподобных объектов Python, таких как 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>'
    

(Предложено Раймондом Хеттингером и реализовано Эриком Смитом в bpo-6081).

  • Интерпретатор теперь можно запускать с опцией quiet, -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)
    

    (Внесено Марцином Войдыром в bpo-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
    

    (Обнаружено Юрием Селивановым и исправлено Бенджамином Петерсоном; bpo-9666).

  • str() плавающего или комплексного числа теперь совпадает с его repr(). Ранее форма str() была короче, но это приводило к путанице и больше не нужно, так как по умолчанию отображается кратчайший возможный repr():

    >>> import math
    >>> repr(math.pi)
    '3.141592653589793'
    >>> str(math.pi)
    '3.141592653589793'
    

    (Предложено и реализовано Марком Дикинсоном; bpo-9337).

  • У объектов memoryview теперь есть метод release(), и они также теперь поддерживают протокол управления контекстом. Это позволяет своевременно освободить все ресурсы, которые были получены при запросе буфера от исходного объекта.

    >>> with memoryview(b'abcdefgh') as v:
    ...     print(v.tolist())
    [97, 98, 99, 100, 101, 102, 103, 104]
    

    (Добавлено Антуаном Питру; bpo-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()
            # implicit "del e" here
    

    (См. bpo-4617).

  • Struct sequence types теперь являются подклассами tuple. Это означает, что структуры на C, такие как те, что возвращаются с помощью os.stat(), time.gmtime() и sys.version_info, теперь работают как named tuple и работают с функциями и методами, которые ожидают кортеж в качестве аргумента. Это большой шаг вперед к тому, чтобы сделать структуры C такими же гибкими, как их чисто питоновские аналоги:

    >>> import sys
    >>> isinstance(sys.version_info, tuple)
    True
    >>> 'Version %d.%d.%d %s(%d)' % sys.version_info 
    'Version 3.2.0 final(0)'
    

    (Предложено Arfrever Frehtes Taifersar Arahesis и реализовано Benjamin Peterson в bpo-8413).

  • Теперь предупреждениями легче управлять, используя переменную окружения PYTHONWARNINGS в качестве альтернативы использованию -W в командной строке:

    $ export PYTHONWARNINGS='ignore::RuntimeWarning::,once::UnicodeWarning::'
    

    (Предложено Барри Варшавом и реализовано Филипом Дженви в bpo-7301).

  • Была добавлена новая категория предупреждений, ResourceWarning. Оно выдается при обнаружении потенциальных проблем с потреблением ресурсов или очисткой. По умолчанию оно отключено в обычных сборках релизов, но может быть включено средствами, предоставляемыми модулем warnings, или в командной строке.

    При завершении работы интерпретатора выдается сообщение ResourceWarning, если список gc.garbage не пуст, а если установлен gc.DEBUG_UNCOLLECTABLE, то выводятся все не собираемые объекты. Это сделано для того, чтобы программист знал, что его код содержит проблемы с завершением объектов.

    Сообщение ResourceWarning также выдается, когда объект file object уничтожается без явного закрытия. Хотя деаллокатор такого объекта гарантирует, что он закроет базовый ресурс операционной системы (обычно дескриптор файла), задержка в деаллокации объекта может привести к различным проблемам, особенно в Windows. Вот пример включения предупреждения из командной строки:

    $ python -q -Wdefault
    >>> f = open("foo", "wb")
    >>> del f
    __main__:1: ResourceWarning: unclosed file <_io.BufferedWriter name='foo'>
    

    (Добавлено Антуаном Питру и Георгом Брандлом в bpo-10093 и bpo-477863).

  • Объекты range теперь поддерживают методы index и count. Это часть усилий, направленных на то, чтобы больше объектов полностью реализовывали collections.Sequence abstract base class. В результате язык получит более единообразный 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)
    

    (При участии Даниэля Штуцбаха в bpo-9213, Александра Белопольского в bpo-2690 и Ника Коглана в bpo-10889).

  • Встроенная функция callable() из Py2.x была воскрешена. Она предоставляет краткую и читаемую альтернативу использованию abstract base class в выражении типа isinstance(x, collections.Callable):

    >>> callable(max)
    True
    >>> callable(20)
    False
    

    (См. bpo-10518).

  • Механизм импорта Python теперь может загружать модули, установленные в каталогах с не-ASCII символами в имени пути. Это решило усугубляющую проблему с домашними каталогами для пользователей с не-ASCII символами в имени пользователя.

(Требуется обширная работа Виктора Стиннера в bpo-9425).

Новые, улучшенные и устаревшие модули

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

Самая большая новость для Python 3.2 - пакет email, модуль mailbox и модули nntplib теперь корректно работают с моделью байт/текст в Python 3. Впервые реализована корректная обработка сообщений со смешанными кодировками.

Во всей стандартной библиотеке больше внимания уделяется кодировкам и вопросам соотношения текста и байтов. В частности, при взаимодействии с операционной системой теперь лучше обмениваться данными, отличными от ASCII, используя кодировку Windows MBCS, кодировки, учитывающие локальные особенности, или UTF-8.

Еще один значительный выигрыш - добавление значительно лучшей поддержки SSL-соединений и сертификатов безопасности.

Кроме того, теперь все больше классов реализуют оператор context manager для поддержки удобной и надежной очистки ресурсов с помощью оператора with.

e-mail

Удобство использования пакета email в Python 3 было в основном исправлено благодаря активным усилиям Р. Дэвида Мюррея. Проблема заключалась в том, что электронные письма обычно читаются и хранятся в виде текста bytes, а не str, и они могут содержать несколько кодировок в пределах одного письма. Поэтому пакет email необходимо было расширить для разбора и генерации электронных сообщений в формате байтов.

  • Новые функции message_from_bytes() и message_from_binary_file(), а также новые классы BytesFeedParser и BytesParser позволяют разбирать данные двоичных сообщений на объекты модели.

  • Если в модель введены байты, get_payload() по умолчанию декодирует тело сообщения, имеющее Content-Transfer-Encoding значение 8bit, используя charset, указанный в MIME-заголовках, и возвращает результирующую строку.

  • Если в модель вводятся байты, то Generator преобразует тела сообщений, которые имеют Content-Transfer-Encoding в 8 бит, чтобы вместо этого иметь 7 бит Content-Transfer-Encoding.

    Заголовки с некодированными байтами, не относящимися к ASCII, считаются RFC 2047- закодированными с использованием неизвестного-8-битного набора символов.

  • Новый класс BytesGenerator производит байты в качестве выходных данных, сохраняя все неизменные данные не ASCII, которые присутствовали во входных данных, использованных для построения модели, включая тела сообщений с Content-Transfer-Encoding в 8bit.

  • Класс smtplib Класс SMTP теперь принимает байтовую строку в качестве аргумента msg для метода sendmail(), а новый метод send_message() принимает объект Message и может по желанию получать адреса from_addr и to_addrs непосредственно из объекта.

(Предложено и реализовано Р. Дэвидом Мюрреем, bpo-4661 и bpo-10321).

дерево элементов

Пакет xml.etree.ElementTree и его аналог xml.etree.cElementTree были обновлены до версии 1.3.

Добавлено несколько новых и полезных функций и методов:

Два метода были устаревшими:

  • Вместо xml.etree.ElementTree.getchildren() используйте list(elem).

  • Вместо xml.etree.ElementTree.getiterator() используйте Element.iter.

Подробности обновления смотрите в разделе Introducing ElementTree на сайте Фредрика Лунда.

(При участии Флорана Ксиклуна и Фредрика Лунда, bpo-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)
    

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

    >>> get_phone_number.cache_clear()
    

    (При участии Раймонда Хеттингера и с использованием дизайнерских идей Джима Бейкера, Мики Тебеки и Ника Коглана; см. recipe 498245, recipe 577479, bpo-10586 и bpo-10593).

  • Декоратор functools.wraps() теперь добавляет атрибут __wrapped__, указывающий на исходную вызываемую функцию. Это позволяет интроспектировать обернутые функции. Он также копирует __annotations__, если он определен. И теперь он также изящно пропускает недостающие атрибуты, такие как __doc__, которые могут быть не определены для обернутой вызываемой функции.

    В приведенном выше примере кэш можно удалить, восстановив исходную функцию:

    >>> get_phone_number = get_phone_number.__wrapped__    # uncached function
    

    (Авторы Ник Коглан и Терренс Коул; bpo-9567, bpo-3445 и bpo-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 остальные методы сравнения заполняются автоматически.

    (Предоставлено Раймондом Хеттингером.)

  • Чтобы облегчить перенос программ с Python 2, функция functools.cmp_to_key() преобразует функцию сравнения старого стиля в современную key function:

    >>> # locale-aware sort order
    >>> sorted(iterable, key=cmp_to_key(locale.strcoll)) 
    

    Примеры сортировки и краткое руководство по сортировке см. в руководстве Sorting HowTo.

    (Предоставлено Раймондом Хеттингером.)

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))      # cumulative probability distribution
    [0.1, 0.5, 0.7, 1.0]
    

    Пример использования accumulate() см. в разделе examples for the random module.

    (При участии Раймонда Хеттингера и с учетом предложений по дизайну от Марка Дикинсона).

коллекции

  • Класс collections.Counter теперь имеет две формы вычитания на месте: существующий оператор -= для saturating subtraction и новый метод subtract() для обычного вычитания. Первый подходит для multisets, в которых есть только положительные отсчеты, а второй больше подходит для случаев использования, допускающих отрицательные отсчеты:

    >>> from collections import Counter
    >>> tally = Counter(dogs=5, cats=3)
    >>> tally -= Counter(dogs=2, cats=8)    # saturating subtraction
    >>> tally
    Counter({'dogs': 3})
    
    >>> tally = Counter(dogs=5, cats=3)
    >>> tally.subtract(dogs=2, cats=8)      # regular subtraction
    >>> tally
    Counter({'dogs': 3, 'cats': -5})
    

    (Предоставлено Раймондом Хеттингером.)

  • В классе collections.OrderedDict появился новый метод move_to_end(), который принимает существующую клавишу и перемещает ее на первую или последнюю позицию в упорядоченной последовательности.

    По умолчанию элемент перемещается на последнюю позицию. Это эквивалентно обновлению записи с помощью od[k] = od.pop(k).

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

    >>> from collections import OrderedDict
    >>> 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']
    

    (Предоставлено Раймондом Хеттингером.)

  • Класс collections.deque обзавелся двумя новыми методами count() и reverse(), которые делают его более заменяемым для объектов list:

    >>> from collections import deque
    >>> d = deque('simsalabim')
    >>> d.count('s')
    2
    >>> d.reverse()
    >>> d
    deque(['m', 'i', 'b', 'a', 'l', 'a', 's', 'm', 'i', 's'])
    

    (Предоставлено Раймондом Хеттингером.)

нарезка резьбы

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

Барьеры могут работать с произвольным числом потоков. Это обобщение Rendezvous, которое определяется только для двух потоков.

Объекты Barrier, реализованные в виде двухфазного циклического барьера, подходят для использования в циклах. Раздельные фазы заполнения и слива гарантируют, что все потоки будут освобождены (слиты) до того, как любой из них сможет вернуться в цикл и снова войти в барьер. Барьер полностью сбрасывается после каждого цикла.

Пример использования барьеров:

from threading import Barrier, Thread

def get_votes(site):
    ballots = conduct_election(site)
    all_polls_closed.wait()        # do not count until all polls are closed
    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) в bpo-8777).

время и дата

  • В модуле 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()      # remove the default warning filters
    
    >>> time.accept2dyear = True      # guess whether 11 means 11 or 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     # use the full range of allowable dates
    >>> 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() будут принимать весь диапазон, поддерживаемый соответствующими функциями операционной системы.

(При участии Александра Белопольского и Виктора Стиннера в bpo-1289118, bpo-5094, bpo-6641, bpo-2706, bpo-1777412, bpo-8013 и bpo-10827).

математика

Модуль math был обновлен шестью новыми функциями, вдохновленными стандартом C99.

Функция isfinite() обеспечивает надежный и быстрый способ определения особых значений. Она возвращает True для обычных чисел и False для Nan или Infinity:

>>> from math import isfinite
>>> [isfinite(x) for x in (123, 4.56, float('Nan'), float('Inf'))]
[True, True, False, False]

Функция expm1() вычисляет e**x-1 для малых значений x без потери точности, которая обычно сопровождает вычитание почти равных величин:

>>> from math import expm1
>>> expm1(0.013671875)   # more accurate way to compute e**x-1 for a small x
0.013765762467652909

Функция erf() вычисляет интеграл вероятности или Gaussian error function. Дополнительной функцией ошибки, erfc(), является 1 - erf(x):

>>> from math import erf, erfc, sqrt
>>> erf(1.0/sqrt(2.0))   # portion of normal distribution within 1 standard deviation
0.682689492137086
>>> erfc(1.0/sqrt(2.0))  # portion of normal distribution outside 1 standard deviation
0.31731050786291404
>>> erf(1.0/sqrt(2.0)) + erfc(1.0/sqrt(2.0))
1.0

Функция gamma() является непрерывным расширением функции факториала. Подробности см. на сайте https://en.wikipedia.org/wiki/Gamma_function. Поскольку функция связана с факториалами, она становится большой даже при малых значениях x, поэтому существует также функция lgamma() для вычисления натурального логарифма гамма-функции:

>>> from math import gamma, lgamma
>>> gamma(7.0)           # six factorial
720.0
>>> lgamma(801.0)        # log(800 factorial)
4551.950730698041

(Предоставлено Марком Дикинсоном.)

abc

Модуль abc теперь поддерживает abstractclassmethod() и abstractstaticmethod().

Эти инструменты позволяют определить abstract base class, для реализации которого требуется определенный classmethod() или staticmethod():

class Temperature(metaclass=abc.ABCMeta):
    @abc.abstractclassmethod
    def from_fahrenheit(cls, t):
        ...
    @abc.abstractclassmethod
    def from_celsius(cls, t):
        ...

(Заплатка предоставлена Дэниелом Урбаном; bpo-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'

(Внесено Антуаном Питру в bpo-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'>

(Внесено Раймондом Хеттингером в bpo-9826 и bpo-9840).

ведение журнала

Помимо описанной выше конфигурации на основе словаря, пакет logging имеет множество других улучшений.

Документация по логированию была дополнена basic tutorial, advanced tutorialи cookbookрецептами логирования. Эти документы - самый быстрый способ узнать о логировании.

Функция установки 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")

Если перед возникновением события регистрации не задана конфигурация, то для событий уровня WARNING и выше теперь существует конфигурация по умолчанию, использующая значение StreamHandler, направленное на sys.stderr. Раньше событие, произошедшее до установки конфигурации, в зависимости от значения 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"

(Новый диалект, предложенный Джеем Талботом в bpo-5975, и новый метод, предложенный Эдом Абрахамом в bpo-1537721).

contextlib

Существует новый и немного умопомрачительный инструмент ContextDecorator, который помогает создать context manager, выполняющий двойную функцию декоратора функций.

В качестве удобства эта новая функциональность используется contextmanager(), так что для поддержки обеих ролей не требуется дополнительных усилий.

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

Например, иногда полезно обернуть функции или группы операторов логгером, который может отслеживать время входа и время выхода. Вместо того чтобы писать декоратор функции и менеджер контекста для задачи, contextmanager() предоставляет обе возможности в одном определении:

from contextlib import contextmanager
import logging

logging.basicConfig(level=logging.INFO)

@contextmanager
def track_entry_and_exit(name):
    logging.info('Entering: %s', name)
    yield
    logging.info('Exiting: %s', 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 вернуть экземпляр журнала для использования в теле вложенных операторов.

(Предоставлено Майклом Фоордом в bpo-9110).

десятичные и дробные числа

Марк Дикинсон разработал элегантную и эффективную схему, гарантирующую, что различные числовые типы данных будут иметь одинаковое хэш-значение, когда их фактические значения равны (bpo-8188):

assert hash(Fraction(3, 2)) == hash(1.5) == \
       hash(Decimal("1.5")) == hash(complex(1.5, 0))

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

>>> sys.hash_info 
sys.hash_info(width=64, modulus=2305843009213693951, inf=314159, nan=0, imag=1000003)

Раннее решение об ограничении совместимости различных числовых типов было смягчено. По-прежнему не поддерживается (и не рекомендуется) неявное смешивание в арифметических выражениях, таких как Decimal('1.1') + float('1.1'), так как при этом теряется информация в процессе конструирования двоичного float. Однако, поскольку существующее значение с плавающей точкой может быть без потерь преобразовано в десятичное или рациональное представление, имеет смысл добавить их в конструктор и поддерживать сравнения смешанного типа.

  • Конструктор decimal.Decimal теперь принимает объекты float напрямую, поэтому больше нет необходимости использовать метод from_float() (bpo-8257).

  • Теперь полностью поддерживаются сравнения смешанных типов, так что объекты Decimal можно напрямую сравнивать с float и fractions.Fraction (bpo-2531 и bpo-8188).

Аналогичные изменения были внесены в fractions.Fraction, так что методы from_float() и from_decimal() больше не нужны (bpo-8294):

>>> from decimal import Decimal
>>> from fractions import Fraction
>>> Decimal(1.1)
Decimal('1.100000000000000088817841970012523233890533447265625')
>>> Fraction(1.1)
Fraction(2476979795053773, 2251799813685248)

Еще одно полезное изменение для модуля decimal заключается в том, что атрибут Context.clamp теперь является общедоступным. Это полезно при создании контекстов, соответствующих десятичным форматам обмена, указанным в IEEE 754 (см. bpo-8540).

(Предоставлено Марком Дикинсоном и Раймондом Хеттингером).

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

Другие файлоподобные объекты, такие как mmap.mmap и fileinput.input(), также обзавелись автозакрывающимися контекстными менеджерами:

with fileinput.input(files=('log1.txt', 'log2.txt')) as f:
    for line in f:
        process(line)

(При участии Тарека Зиаде и Джампаоло Родола в bpo-4972 и Георга Брандла в bpo-8046 и bpo-1286).

Класс FTP_TLS теперь принимает параметр context, который представляет собой объект ssl.SSLContext, позволяющий объединить параметры конфигурации SSL, сертификаты и закрытые ключи в единую (потенциально долгоживущую) структуру.

(Предоставлено Джампаоло Родола; bpo-8806)

popen

Функции os.popen() и subprocess.Popen() теперь поддерживают операторы with для автоматического закрытия дескрипторов файлов.

(При участии Антуана Питру и Брайана Кертина в bpo-7461 и bpo-10554).

выберите

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

>>> import select
>>> select.PIPE_BUF  
512

(Доступно для Unix-систем. Исправление Себастьена Сабле в bpo-9862)

gzip и zipfile

gzip.GzipFile теперь реализует io.BufferedIOBase abstract base class (за исключением truncate()). Он также имеет метод peek() и поддерживает файловые объекты без поиска и с нулевым пакетом.

Модуль gzip также получил функции compress() и decompress() для более удобного сжатия и распаковки в памяти. Помните, что перед сжатием и распаковкой текст должен быть закодирован как bytes:

>>> import gzip
>>> s = 'Three shall be the number thou shalt count, '
>>> s += 'and the number of the counting shall be three'
>>> b = s.encode()                        # convert to utf-8
>>> len(b)
89
>>> c = gzip.compress(b)
>>> len(c)
77
>>> gzip.decompress(c).decode()[:42]      # decompress and convert to text
'Three shall be the number thou shalt count'

(Материалы предоставлены Анандом Б. Пиллаем в bpo-3488; Антуаном Питру, Ниром Айдесом и Брайаном Кертином в bpo-9962, bpo-1675951, bpo-7471 и bpo-2846).

Кроме того, класс zipfile.ZipExtFile был внутренне переработан для представления файлов, хранящихся в архиве. Новая реализация значительно быстрее и может быть обернута в объект io.BufferedReader для большего ускорения. Также решена проблема, когда чередующиеся вызовы read и readline давали неверные результаты.

(Патч прислал Нир Айдес в bpo-7610).

tarfile

Класс TarFile теперь можно использовать в качестве менеджера контекста. Кроме того, его метод add() имеет новую опцию filter, которая контролирует, какие файлы добавляются в архив, и позволяет редактировать метаданные файла.

Новый параметр filter заменяет старый, менее гибкий параметр exclude, который в настоящее время устарел. Если указан, необязательный параметр filter должен быть значением keyword argument. Пользовательская функция 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

(Предложено Тареком Зиаде и реализовано Ларсом Густебелем в bpo-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'}

(Предложено Карлом Чене в bpo-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(), для кодирования и декодирования имен файлов:

>>> import os
>>> filename = 'Sehenswürdigkeiten'
>>> os.fsencode(filename)
b'Sehensw\xc3\xbcrdigkeiten'

Некоторые операционные системы позволяют напрямую обращаться к закодированным байтам в среде. Если это так, то константа os.supports_bytes_environ будет равна true.

Для прямого доступа к закодированным переменным окружения (если они доступны) используйте новую функцию os.getenvb() или os.environb, которая является байтовой версией os.environ.

(Предоставлено Виктором Стиннером.)

ШУТИЛ

Функция shutil.copytree() имеет два новых параметра:

  • ignore_dangling_symlinks: когда symlinks=False, чтобы функция копировала файл, на который указывает симлинк, а не сам симлинк. Эта опция не будет выдавать ошибку, если файл не существует.

  • copy_function: вызываемая функция, которая будет использоваться для копирования файлов. По умолчанию используется shutil.copy2().

(Предоставлено Тареком Зиаде.)

Кроме того, модуль shutil теперь поддерживает archiving operations для zip-файлов, несжатых tar-файлов, gzippedant tar-файлов и bzippedant tar-файлов. Также есть функции для регистрации дополнительных форматов архивных файлов (например, xz-сжатых tar-файлов или пользовательских форматов).

Основными функциями являются make_archive() и unpack_archive(). По умолчанию обе работают с текущим каталогом (который может быть задан с помощью os.chdir()) и с любыми подкаталогами. Имя архивного файла должно быть указано полным именем пути. Архивация является неразрушающей (исходные файлы остаются без изменений).

>>> import shutil, pprint

>>> os.chdir('mydata')  # change to the source directory
>>> f = shutil.make_archive('/var/backup/mydata',
...                         'zip')      # archive the current directory
>>> f                                   # show the name of archive
'/var/backup/mydata.zip'
>>> os.chdir('tmp')                     # change to an unpacking
>>> shutil.unpack_archive('/var/backup/mydata.zip')  # recover the data

>>> pprint.pprint(shutil.get_archive_formats())  # display known formats
[('bztar', "bzip2'ed tar-file"),
 ('gztar', "gzip'ed tar-file"),
 ('tar', 'uncompressed tar file'),
 ('zip', 'ZIP file')]

>>> shutil.register_archive_format(     # register a new archive format
...     name='xz',
...     function=xz.compress,           # callable archiving function
...     extra_args=[('level', 8)],      # arguments to the function
...     description='xz compression'
... )

(Предоставлено Тареком Зиаде.)

sqlite3

Модуль sqlite3 был обновлен до версии pysqlite 2.6.0. В нем появились две новые возможности.

  • Атрибут sqlite3.Connection.in_transit является истинным, если существует активная транзакция для незафиксированных изменений.

  • Методы sqlite3.Connection.enable_load_extension() и sqlite3.Connection.load_extension() позволяют загружать расширения SQLite из файлов «.so». Одним из известных расширений является расширение полнотекстового поиска, распространяемое вместе с SQLite.

(При участии Р. Дэвида Мюррея и Шашвата Ананда; bpo-8845).

html

Появился новый модуль html с единственной функцией escape(), которая используется для экранирования зарезервированных символов из HTML-разметки:

>>> import html
>>> html.escape('x > 2 && x < 7')
'x &gt; 2 &amp;&amp; x &lt; 7'

сокет

Модуль socket получил два новых улучшения.

  • У объектов Socket теперь есть метод detach(), который переводит сокет в закрытое состояние без фактического закрытия базового дескриптора файла. Последний может быть повторно использован для других целей. (Добавлено Антуаном Питру; bpo-8524).

  • socket.create_connection() теперь поддерживает протокол управления контекстом для безусловного поглощения исключений socket.error и закрытия сокета по завершении работы. (Внесено Джампаоло Родола; bpo-9794).

ssl

Модуль ssl добавил ряд функций для удовлетворения общих требований к безопасным (зашифрованным, аутентифицированным) интернет-соединениям:

  • Новый класс SSLContext служит контейнером для постоянных данных SSL, таких как настройки протокола, сертификаты, закрытые ключи и различные другие параметры. Он включает wrap_socket() для создания SSL-сокета из SSL-контекста.

  • Новая функция, ssl.match_hostname(), поддерживает проверку подлинности сервера для протоколов более высокого уровня, реализуя правила HTTPS (из RFC 2818), которые также подходят для других протоколов.

  • Функция конструктора ssl.wrap_socket() теперь принимает аргумент ciphers. В строке ciphers перечисляются допустимые алгоритмы шифрования в формате, описанном в OpenSSL documentation.

  • При подключении к последним версиям 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 (целое число).

(Внесено Антуаном Питру в bpo-8850, bpo-1589, bpo-8322, bpo-5639, bpo-4870, bpo-8484 и bpo-8321).

nntp

Модуль nntplib имеет обновленную реализацию с улучшенной семантикой байтов и текста, а также более практичными API. Эти улучшения нарушают совместимость с версией nntplib в Python 3.1, которая сама по себе была частично неработоспособной.

Также добавлена поддержка безопасных соединений через неявный (с использованием nntplib.NNTP_SSL) и явный (с использованием nntplib.NNTP.starttls()) TLS.

(При участии Антуана Питру из bpo-9360 и Эндрю Ванта из bpo-1926).

сертификаты

http.client.HTTPSConnection, urllib.request.HTTPSHandler и urllib.request.urlopen() теперь принимают необязательные аргументы, чтобы обеспечить проверку сертификата сервера по набору центров сертификации, как это рекомендуется при публичном использовании HTTPS.

(Добавлено Антуаном Питру, bpo-9003).

imaplib

Поддержка явного TLS для стандартных соединений IMAP4 была добавлена с помощью нового метода imaplib.IMAP4.starttls.

(Предоставлено Лоренцо М. Катуччи и Антуаном Питру, bpo-4471).

http.client

В модуле http.client было произведено несколько небольших улучшений API. Простые ответы HTTP 0.9 старого образца больше не поддерживаются, а параметр strict во всех классах устарел.

Классы HTTPConnection и HTTPSConnection теперь имеют параметр source_address для кортежа (host, port), указывающего, откуда осуществляется HTTP-соединение.

В HTTPSConnection добавлена поддержка проверки сертификатов и виртуальных хостов HTTPS.

Метод request() на объектах соединения позволял использовать необязательный аргумент body, чтобы можно было передать содержимое запроса через file object. Удобно, что аргумент body теперь также принимает объект iterable, если он включает явный заголовок Content-Length. Этот расширенный интерфейс гораздо более гибкий, чем раньше.

Чтобы установить HTTPS-соединение через прокси-сервер, есть новый метод set_tunnel(), который задает хост и порт для туннелирования HTTP Connect.

Чтобы соответствовать поведению http.server, клиентская библиотека HTTP теперь также кодирует заголовки в кодировке ISO-8859-1 (Latin-1). Она уже делала это для входящих заголовков, так что теперь поведение согласовано как для входящего, так и для исходящего трафика. (См. работу Армина Ронахера в bpo-10980).

unittest

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

  • Вызов командной строки python -m unittest теперь может принимать пути к файлам вместо имен модулей для запуска определенных тестов (bpo-10620). Новая функция обнаружения тестов может находить тесты внутри пакетов, определяя местоположение любого теста, импортируемого из каталога верхнего уровня. Каталог верхнего уровня можно указать с помощью опции -t, шаблон для поиска файлов - с помощью -p, а каталог для начала обнаружения - с помощью -s:

    $ python -m unittest discover -s my_proj_dir -p _test.py
    

    (Предоставлено Майклом Фоордом.)

  • Экспериментировать в интерактивной подсказке стало проще, поскольку класс unittest.TestCase теперь можно инстанцировать без аргументов:

    >>> from unittest import TestCase
    >>> TestCase().assertEqual(pow(2, 3), 8)
    

    (Предоставлено Майклом Фоордом.)

  • Модуль unittest содержит два новых метода, assertWarns() и assertWarnsRegex(), для проверки того, что данный тип предупреждения вызван тестируемым кодом:

    with self.assertWarns(DeprecationWarning):
        legacy_function('XYZ')
    

    (Предоставлено Антуаном Питру, bpo-9754).

    Еще один новый метод, assertCountEqual(), используется для сравнения двух итеративных таблиц, чтобы определить, одинаково ли количество элементов в них (присутствуют ли одни и те же элементы с одинаковым количеством вхождений независимо от порядка):

    def test_anagram(self):
        self.assertCountEqual('algorithm', 'logarithm')
    

    (Предоставлено Раймондом Хеттингером.)

  • Главной особенностью модуля unittest является попытка выдать содержательную диагностику при неудачном выполнении теста. Когда это возможно, сбой записывается вместе с разницей в результатах. Это особенно полезно для анализа лог-файлов неудачных запусков тестов. Однако, поскольку диффы иногда могут быть очень объемными, появился новый атрибут maxDiff, задающий максимальную длину отображаемых диффов.

  • Кроме того, имена методов в модуле подверглись ряду чисток.

    Например, assertRegex() - это новое название для assertRegexpMatches(), который был назван неправильно, потому что в тесте используется re.search(), а не re.match(). Другие методы, использующие регулярные выражения, теперь называются сокращенно «Regex», а не «Regexp» - это соответствует названиям, используемым в других реализациях unittest, соответствует старому названию модуля re в Python и имеет однозначный верблюжий регистр.

    (Внесено Раймондом Хеттингером и реализовано Эцио Мелотти).

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

    Старое имя

    Предпочитаемое имя

    assert_()

    assertTrue()

    assertEquals()

    assertEqual()

    assertNotEquals()

    assertNotEqual()

    assertAlmostEquals()

    assertAlmostEqual()

    assertNotAlmostEquals()

    assertNotAlmostEqual()

    Аналогично, методы TestCase.fail*, устаревшие в Python 3.1, как ожидается, будут удалены в Python 3.3.

    (Предоставлено Эцио Мелотти; bpo-9424).

  • Метод assertDictContainsSubset() был устаревшим, потому что был неправильно реализован с аргументами в неправильном порядке. Это создавало трудноотлаживаемые оптические иллюзии, при которых тесты типа TestCase().assertDictContainsSubset({'a':1, 'b':2}, {'a':1}) проваливались.

    (Предоставлено Раймондом Хеттингером.)

случайно

Целочисленные методы в модуле random теперь лучше справляются с получением равномерных распределений. Ранее они вычисляли выборки с помощью int(n*random()), что приводило к небольшому смещению, когда n не являлось степенью двойки. Теперь выборки производятся из диапазона до следующей степени двойки, и выборка сохраняется только тогда, когда она попадает в диапазон 0 <= x < n. Затронуты функции и методы randrange(), randint(), choice(), shuffle() и sample().

(Внесено Раймондом Хеттингером; bpo-9025).

poplib

Класс POP3_SSL теперь принимает параметр context, который представляет собой объект ssl.SSLContext, позволяющий объединить параметры конфигурации SSL, сертификаты и закрытые ключи в единую (потенциально долгоживущую) структуру.

(Предоставлено Джампаоло Родола; bpo-8807)

asyncore

asyncore.dispatcher теперь предоставляет метод handle_accepted(), возвращающий пару (sock, addr), который вызывается, когда соединение с новой удаленной конечной точкой действительно установлено. Предполагается, что он будет использоваться в качестве замены старого handle_accept() и избавит пользователя от необходимости вызывать accept() напрямую.

(Предоставлено Джампаоло Родола; bpo-6706)

tempfile

В модуле tempfile появился новый менеджер контекста TemporaryDirectory, который обеспечивает легкую детерминированную очистку временных каталогов:

with tempfile.TemporaryDirectory() as tmpdirname:
    print('created temporary dir:', tmpdirname)

(При участии Нила Шеменауэра и Ника Коглана; bpo-5178).

осмотреть

  • В модуле 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'
    

    (При участии Родольфо Экхардта и Ника Коглана, bpo-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>
    

(Предоставлено Майклом Фоордом.)

pydoc

Модуль pydoc теперь предоставляет значительно улучшенный интерфейс веб-сервера, а также новую опцию командной строки -b для автоматического открытия окна браузера для отображения этого сервера:

$ pydoc3.2 -b

(Внесено Роном Адамом; bpo-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, и позволяют воочию убедиться в том, что синтаксис языка работает «под капотом».

(Предоставлено Ником Когланом из bpo-9147).

dbm

Все модули баз данных теперь поддерживают методы get() и setdefault().

(Предложено Рэем Алленом в bpo-9523).

ctypes

Новый тип ctypes.c_ssize_t представляет тип данных C ssize_t.

сайт

В модуле site появились три новые функции, полезные для составления отчетов о деталях конкретной установки Python.

  • getsitepackages() перечисляет все глобальные каталоги пакетов сайта.

  • 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'

Удобно, что некоторые функции сайта доступны прямо из командной строки:

$ python -m site --user-base
/Users/raymondhettinger/.local
$ python -m site --user-site
/Users/raymondhettinger/.local/lib/python3.2/site-packages

(Предоставлено Тареком Зиаде в bpo-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, чтение непосредственно из словарей и строк.

(Все изменения внесены Лукашем Ланга).

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() теперь возвращает named tuple:

>>> 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 либо строку, либо тип байта. Если это строка, то параметры 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'

Как подробно описано в Разбор байтов в кодировке ASCII, все функции 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'')

(Работы Ника Коглана, Дэна Мана и Сентхила Кумарана в bpo-2987, bpo-5468 и bpo-9873).

почтовый ящик

Благодаря совместным усилиям Р. Дэвида Мюррея, модуль mailbox был исправлен для Python 3.2. Проблема заключалась в том, что почтовый ящик изначально разрабатывался с текстовым интерфейсом, но сообщения электронной почты лучше всего представлять с помощью bytes, поскольку различные части сообщения могут иметь разные кодировки.

Решение использовало бинарную поддержку пакета email для разбора произвольных почтовых сообщений. Кроме того, решение потребовало внесения ряда изменений в API.

Как и ожидалось, метод add() для объектов mailbox.Mailbox теперь принимает двоичные данные.

StringIO и ввод из текстового файла устарели. Кроме того, строковый ввод будет завершаться преждевременно, если используются символы не ASCII. Ранее это происходило, когда письмо обрабатывалось на более позднем шаге.

Также появилась поддержка двоичного вывода. Метод get_file() теперь возвращает файл в двоичном режиме (раньше он некорректно устанавливал текстовый режим). Также появился новый метод get_bytes(), который возвращает bytes представление сообщения, соответствующего заданному ключу.

По-прежнему можно получить недвоичный вывод, используя метод get_string() старого API, но такой подход не очень полезен. Вместо этого лучше всего извлекать сообщения из объекта Message или загружать их из двоичного ввода.

(Внесено Р. Дэвидом Мюрреем при участии Штеффена Даоде Нурпмесо и первоначального патча Виктора Стиннера в bpo-9124).

turtledemo

Демонстрационный код для модуля turtle был перемещен из каталога Demo в основную библиотеку. Он включает в себя более дюжины примеров скриптов с живым отображением. Находясь на sys.path, он теперь может быть запущен непосредственно из командной строки:

$ python -m turtledemo

(Перемещено из каталога Demo Александром Белопольским в bpo-10199).

Многопоточность

  • Механизм сериализации выполнения параллельно работающих потоков Python (обычно известный как GIL или глобальная блокировка интерпретатора) был переписан. Среди целей были более предсказуемые интервалы переключения и снижение накладных расходов, связанных с борьбой за блокировку и количеством последующих системных вызовов. Понятие «контрольного интервала» для переключения потоков было отменено и заменено абсолютной длительностью, выраженной в секундах. Этот параметр настраивается с помощью sys.setswitchinterval(). В настоящее время по умолчанию он равен 5 миллисекундам.

    Дополнительные подробности о реализации можно прочитать в python-dev mailing-list message (однако «приоритетные запросы», как показано в этом сообщении, не были сохранены для включения).

    (Предоставлено Антуаном Питру.)

  • Регулярные и рекурсивные блокировки теперь принимают необязательный аргумент timeout для своего метода acquire(). (Внесено Антуаном Питру; bpo-7316).

  • Аналогично, threading.Semaphore.acquire() также получил аргумент timeout. (Внесено Торстеном Ландшоффом; bpo-850728).

  • Регулярное и рекурсивное получение блокировок теперь может быть прервано сигналами на платформах, использующих Pthreads. Это означает, что Python-программы, зашедшие в тупик при получении блокировок, могут быть успешно завершены путем многократной отправки SIGINT процессу (нажатием клавиши Ctrl+C в большинстве оболочек). (Внесено Ридом Клекнером; bpo-8844).

Оптимизации

Был добавлен ряд небольших улучшений производительности:

  • Оптимизатор Python теперь распознает шаблоны типа x in {1, 2, 3} как тест на принадлежность к набору констант. Оптимизатор преобразует set в frozenset и сохраняет предварительно созданную константу.

    Теперь, когда штраф за скорость исчез, можно начать писать тесты членства, используя set-notation. Этот стиль является одновременно семантически ясным и оперативно быстрым:

    extension = name.rpartition('.')[2]
    if extension in {'xml', 'html', 'xhtml', 'css'}:
        handle(name)
    

    (Патч и дополнительные тесты предоставлены Дэйвом Малкольмом; bpo-6690).

  • Сериализация и несериализация данных с помощью модуля pickle теперь выполняется в несколько раз быстрее.

    (При участии Александра Вассалотти, Антуана Питру и команды Unladen Swallow в bpo-9410 и bpo-3873).

  • Timsort algorithm, используемый в list.sort() и sorted(), теперь работает быстрее и использует меньше памяти при вызове с key function. Раньше каждый элемент списка оборачивался временным объектом, который запоминал значение ключа, связанное с каждым элементом. Теперь два массива ключей и значений сортируются параллельно. Это экономит память, занимаемую обертками сортировки, и время, потерянное на делегирование сравнений.

    (Patch by Daniel Stutzbach in bpo-9915).

  • Повышена производительность декодирования JSON и уменьшено потребление памяти при повторении одной и той же строки для нескольких ключей. Кроме того, при кодировании JSON теперь используется ускорение C, когда аргумент sort_keys равен true.

    (При участии Антуана Питру в bpo-7451 и Раймонда Хеттингера и Антуана Питру в bpo-10314).

  • Рекурсивные блокировки (созданные с помощью API threading.RLock()) теперь имеют реализацию на языке C, которая делает их такими же быстрыми, как и обычные блокировки, и в 10-15 раз быстрее, чем их предыдущая чисто питоновская реализация.

    (Предоставлено Антуаном Питру; bpo-3001)

  • Алгоритм быстрого поиска в stringlib теперь используется методами split(), rsplit(), splitlines() и replace() на объектах bytes, bytearray и str. Аналогично, алгоритм также используется в rfind(), rindex(), rsplit() и rpartition().

    (Патч Флорана Ксиклуна в bpo-7622 и bpo-7462).

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

    (bpo-6713 от Гавейна Болтона, Марка Дикинсона и Виктора Стиннера).

Было сделано еще несколько мелких оптимизаций. Дифференцирование множеств теперь работает быстрее, когда один операнд намного больше другого (исправление Андресса Беннетса в bpo-8685). Метод array.repeat() имеет более быструю реализацию (bpo-1569291 от Александра Белопольского). Метод BaseHTTPRequestHandler имеет более эффективную буферизацию (bpo-3709 от Andrew Schaaf). Функция operator.attrgetter() была ускорена (bpo-10160 Кристоса Георгиу). А ConfigParser загружает многострочные аргументы немного быстрее (bpo-7113 by Łukasz Langa).

Юникод

Стандарт Python был обновлен до версии Unicode 6.0.0. Обновление стандарта добавляет более 2 000 новых символов, включая символы emoji, которые важны для мобильных телефонов.

Кроме того, в обновленном стандарте изменены свойства двух символов каннада (U+0CF1, U+0CF2) и одного числового символа нью-тай-люэ (U+19DA), в результате чего первые могут использоваться в идентификаторах, а вторые дисквалифицированы. Дополнительную информацию см. в разделе Unicode Character Database Changes.

Кодеки

Добавлена поддержка арабской DOS-кодировки cp720 (bpo-1616979).

Кодирование MBCS больше не игнорирует аргумент обработчика ошибок. В строгом режиме по умолчанию она выдает UnicodeDecodeError, когда встречает недекодируемую последовательность байтов, и UnicodeEncodeError для некодируемого символа.

Кодек MBCS поддерживает обработчики ошибок 'strict' и 'ignore' для декодирования и 'strict' и 'replace' для кодирования.

Чтобы эмулировать кодировку MBCS в Python3.1, выберите обработчик 'ignore' для декодирования и 'replace' для кодирования.

В Mac OS X Python декодирует аргументы командной строки с помощью 'utf-8', а не в кодировке локали.

По умолчанию tarfile использует кодировку 'utf-8' в Windows (вместо 'mbcs') и обработчик ошибок 'surrogateescape' во всех операционных системах.

Документация

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

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

  • В некоторых случаях чистый исходный код Python может быть полезным дополнением к документации, поэтому теперь во многих модулях есть быстрые ссылки на последнюю версию исходного кода. Например, в документации к модулю functools в верхней части есть быстрая ссылка с надписью:

    Источниковый код Lib/functools.py.

    (Внесено Раймондом Хеттингером; см. rationale).

  • Документация теперь содержит больше примеров и рецептов. В частности, в модуле re появился обширный раздел Примеры регулярных выражений. Аналогично, модуль itertools продолжает пополняться новыми Рецепты Itertools.

  • Модуль datetime теперь имеет вспомогательную реализацию на чистом Python. Никакая функциональность не была изменена. Это просто предоставляет более легкую для чтения альтернативную реализацию.

    (Внесено Александром Белопольским в bpo-9528).

  • Не поддерживаемая директория Demo была удалена. Некоторые демо-версии были интегрированы в документацию, некоторые были перемещены в каталог Tools/demo, а другие были удалены совсем.

    (Внесено Георгом Брандлом в bpo-7962).

IDLE

  • В меню формата появилась опция очистки исходных файлов путем удаления пробелов в конце.

    (Внесено Раймондом Хеттингером; bpo-5150).

  • IDLE на Mac OS X теперь работает как с Carbon AquaTk, так и с Cocoa AquaTk.

    (При участии Кевина Уолцера, Неда Дейли и Рональда Оусорена; bpo-6075).

Репозиторий кода

В дополнение к существующему репозиторию кода Subversion по адресу https://svn.python.org теперь существует репозиторий Mercurial по адресу https://hg.python.org/.

После выхода версии 3.2 планируется перейти на Mercurial в качестве основного репозитория. Эта распределенная система контроля версий должна облегчить членам сообщества создание и обмен внешними наборами изменений. Подробности см. в PEP 385.

Чтобы научиться пользоваться новой системой контроля версий, смотрите Quick Start или Guide to Mercurial Workflows.

Изменения в сборке и C API

Изменения в процессе сборки Python и в C API включают:

  • Скрипты idle, pydoc и 2to3 теперь устанавливаются с суффиксом make altinstall (bpo-10679), зависящим от версии.

  • Функции C, обращающиеся к базе данных Юникода, теперь принимают и возвращают символы из всего диапазона Юникода, даже при узких сборках Юникода (Py_UNICODE_TOLOWER, Py_UNICODE_ISDECIMAL и другие). Заметное отличие в Python заключается в том, что unicodedata.numeric() теперь возвращает правильное значение для больших кодовых точек, а repr() может считать больше символов пригодными для печати.

    (Сообщено Bupjoe Lee и исправлено Amaury Forgeot D’Arc; bpo-5127).

  • Вычисляемые gotos теперь включены по умолчанию в поддерживаемых компиляторах (которые определяются скриптом configure). Их по-прежнему можно отключить выборочно, указав --without-computed-gotos.

    (Предоставлено Антуаном Питру; bpo-9203)

  • Опция --with-wctype-functions была удалена. Теперь для всех функций используется встроенная база данных юникода.

    (Предоставлено Amaury Forgeot D’Arc; bpo-9210).

  • Теперь хэш-значения имеют новый тип Py_hash_t, который определяется как указатель того же размера. Ранее они имели тип long, который в некоторых 64-битных операционных системах по-прежнему имеет длину только 32 бита. В результате этого исправления set и dict теперь могут содержать больше, чем 2**32 записей в сборках с 64-битными указателями (ранее они могли вырасти до такого размера, но их производительность катастрофически падала).

    (Предложено Раймондом Хеттингером и реализовано Бенджамином Петерсоном; bpo-9778).

  • Новый макрос Py_VA_COPY копирует состояние списка аргументов переменной. Он эквивалентен C99 va_copy, но доступен на всех платформах Python (bpo-2443).

  • Новая функция C API PySys_SetArgvEx() позволяет встроенному интерпретатору устанавливать sys.argv, не изменяя при этом sys.path (bpo-5753).

  • PyEval_CallObject() теперь доступен только в виде макроса. Объявление функции, которое было сохранено по соображениям обратной совместимости, теперь удалено - макрос был введен в 1997 году (bpo-8276).

  • Существует новая функция PyLong_AsLongLongAndOverflow(), которая аналогична PyLong_AsLongAndOverflow(). Они обе служат для преобразования Python int в собственный тип фиксированной ширины и обеспечивают обнаружение случаев, когда преобразование не подходит (bpo-7767).

  • Функция PyUnicode_CompareWithASCIIString() теперь возвращает значение не равно, если строка Python имеет конец NUL.

  • Есть новая функция PyErr_NewExceptionWithDoc(), которая похожа на PyErr_NewException(), но позволяет указывать строку документации. Это позволяет исключениям на C иметь такие же возможности самодокументирования, как и их чисто питоновским аналогам (bpo-7033).

  • При компиляции с опцией --with-valgrind аллокатор pymalloc будет автоматически отключен при работе под Valgrind. Это позволяет улучшить обнаружение утечек памяти при работе под Valgrind, а также использовать преимущества pymalloc в другое время (bpo-2422).

  • Удален формат O? из функций PyArg_Parse. Этот формат больше не используется, и он никогда не был документирован (bpo-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. Дополнительные сведения см. на сайте https://www.python.org/download/mac/tcltk/.

Переход на 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(). Старые имена были устаревшими. (См. bpo-8990).

  • PyArg_Parse*() функции:

    • Формат «t#» был удален: вместо него используйте «s#» или «s*»

    • Форматы «w» и «w#» были удалены: вместо них используйте «w*».

  • Тип PyCObject, устаревший в версии 3.1, был удален. Чтобы обернуть непрозрачные указатели C в объекты Python, следует использовать API PyCapsule. API; новый тип имеет хорошо определенный интерфейс для передачи информации о безопасности типизации и менее сложную сигнатуру для вызова деструктора.

  • Функция 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 с промежуточными таблицами перевода соответствующего типа.

    (Внесено Георгом Брандлом; bpo-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)
    

    (При участии Георга Брандла и Маттиаса Брандстрема; appspot issue 53094).

  • struct.pack() теперь допускает только байты для кода пакета строк s. Раньше он принимал текстовые аргументы и неявно кодировал их в байты с помощью UTF-8. Это было проблематично, поскольку делались предположения о правильности кодировки, а также потому, что кодировка переменной длины может не сработать при записи в сегмент структуры фиксированной длины.

    Код типа struct.pack('<6sHHBBB', 'GIF87a', x, y) следует переписать так, чтобы вместо текста использовались байты, struct.pack('<6sHHBBB', b'GIF87a', x, y).

    (Обнаружено Дэвидом Бизли и исправлено Виктором Стиннером; bpo-10783).

  • Класс xml.etree.ElementTree теперь выдает сообщение xml.etree.ElementTree.ParseError при неудачном разборе. Ранее он выдавал сообщение xml.parsers.expat.ExpatError.

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

  • В subprocess.Popen значение по умолчанию для close_fds теперь True под Unix; под Windows - True, если для трех стандартных потоков установлено значение None, False в противном случае. Ранее значение close_fds по умолчанию всегда было False, что затрудняло устранение ошибок или условий гонки, когда открытые дескрипторы файлов просачивались в дочерний процесс.

  • Поддержка устаревшего HTTP 0.9 была удалена из urllib.request и http.client. Такая поддержка все еще присутствует на стороне сервера (в http.server).

    (Предоставлено Антуаном Питру, bpo-10711).

  • SSL-сокеты в режиме тайм-аута теперь поднимают socket.timeout при возникновении тайм-аута, а не обычную SSLError.

    (Предоставлено Антуаном Питру, bpo-10272).

  • Функции введения в заблуждение PyEval_AcquireLock() и PyEval_ReleaseLock() были официально устаревшими. Вместо них следует использовать API, учитывающие состояние потоков (например, PyEval_SaveThread() и PyEval_RestoreThread()).

  • В связи с рисками безопасности функция asyncore.handle_accept() была устаревшей, и на ее место была добавлена новая функция asyncore.handle_accepted().

    (Внесено Джампаоло Родола в bpo-6706).

  • В связи с новой реализацией GIL, PyEval_InitThreads() больше не может быть вызван перед Py_Initialize().