Что нового в 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 теперь является предпочтительным модулем для обработки командной строки. Более старый модуль все еще остается доступным из-за значительного количества унаследованного кода, который зависит от него.

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

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.)

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

    >>> 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 и реализовано Бенджамином Петерсоном в 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.

электронная почта

Удобство использования пакета 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
    

    Чтобы помочь в выборе эффективного размера кэша, функция wrapped оснащена инструментами для отслеживания статистики кэша:

    >>> 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.

(Внесено Кристьяном Валуром Йонссоном, обзор API сделан Джеффри Ясскином в 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")

Если перед возникновением события регистрации не задана конфигурация, теперь существует конфигурация по умолчанию, использующая StreamHandler, направленную на sys.stderr для событий уровня WARNING или выше. Раньше событие, возникающее до установки конфигурации, либо вызывало исключение, либо молча отбрасывало событие в зависимости от значения параметра logging.raiseExceptions. Новый обработчик по умолчанию хранится в logging.lastResort.

Использование фильтров было упрощено. Вместо того чтобы создавать объект Filter, предикатом может быть любой вызываемый объект Python, который возвращает True или False.

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

csv

Модуль csv теперь поддерживает новый диалект unix_dialect, который применяет кавычки для всех полей и традиционный стиль Unix с '\n' в качестве терминатора строки. Зарегистрированное имя диалекта - unix.

В csv.DictWriter появился новый метод writeheader() для записи начальной строки для документирования имен полей:

>>> import csv, sys
>>> w = csv.DictWriter(sys.stdout, ['name', 'dept'], dialect='unix')
>>> w.writeheader()
"name","dept"
>>> w.writerows([
...     {'name': 'tom', 'dept': 'accounting'},
...     {'name': 'susan', 'dept': 'Salesl'}])
"tom","accounting"
"susan","sales"

(Новый диалект, предложенный Джеем Талботом в 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 будет истиной.

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

(При участии Виктора Стиннера.)

shutil

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

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

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

(При участии Тарека Зиаде.)

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

Основными функциями являются 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.case.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, соответствует старому названию модуля Python re, и имеет однозначный верблюжий регистр.

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

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

    Старое имя

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

    assert_()

    assertTrue()

    assertEquals()

    assertEqual()

    assertNotEquals()

    assertNotEqual()

    assertAlmostEquals()

    assertAlmostEqual()

    assertNotAlmostEquals()

    assertNotAlmostEqual()

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

    (Внесено Эцио Мелотти; 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() перечисляет все глобальные каталоги site-packages.

  • getuserbase() сообщает о базовом каталоге пользователя, в котором могут храниться данные.

  • getusersitepackages() раскрывает путь к директории site-packages для конкретного пользователя.

>>> import site
>>> site.getsitepackages()
['/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/site-packages',
 '/Library/Frameworks/Python.framework/Versions/3.2/lib/site-python',
 '/Library/Python/3.2/site-packages']
>>> site.getuserbase()
'/Users/raymondhettinger/Library/Python/3.2'
>>> site.getusersitepackages()
'/Users/raymondhettinger/Library/Python/3.2/lib/python/site-packages'

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

$ 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. Раньше каждый элемент списка обертывался временным объектом, который запоминал значение ключа, связанное с каждым элементом. Теперь два массива ключей и значений сортируются параллельно. Это экономит память, занимаемую обертками сортировки, и время, потерянное на делегирование сравнений.

    (Патч, созданный Даниэлем Штуцбахом в bpo-9915).

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

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

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

    (Внесено Антуаном Питру; 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 от Christos Georgiou). И ConfigParser немного быстрее загружает многострочные аргументы (bpo-7113 от Лукаша Ланги).

Юникод

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.

Изменения в API Build и C

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

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

  • Функции C, обращающиеся к базе данных Unicode, теперь принимают и возвращают символы из полного диапазона Unicode, даже при узких сборках Unicode (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 была удалена. Встроенная база данных юникода теперь используется для всех функций.

    (Внесено Амори Форжо Д’Арк; 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; новый тип имеет хорошо определенный интерфейс для передачи информации о безопасности типизации и менее сложную сигнатуру для вызова деструктора.

  • Функция 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().

Вернуться на верх