Документация Python неофициальный перевод
Содержание страницы

Что нового в Python 3.2What’s New In Python 3.2

Автор:

Raymond Hettinger

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

См. также

PEP 392 - График выпуска Python 3.2

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

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

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

См. также

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

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

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

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

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

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

import argparse
parser = argparse.ArgumentParser(
            description = 'Manage servers',         # основное описание для справки
            epilog = 'Tested on Solaris and Linux') # отображается после справки
parser.add_argument('action',                       # имя аргумента
            choices = ['deploy', 'start', 'stop'],  # три допустимых значения
            help = 'action on each target')         # сообщение справки
parser.add_argument('targets',
            metavar = 'HOSTNAME',                   # имя переменной, используемое в сообщении справки
            nargs = '+',                            # требуется одна или несколько целей
            help = 'url for target machines')       # пояснение к сообщению справки
parser.add_argument('-u', '--user',                 # опция -u или --user
            required = True,                        # сделать его обязательным аргументом
            help = 'login as user')

Пример вызова парсера для командной строки:

>>> cmd = 'deploy sneezy.example.com sleepy.example.com -u skycaptain'
>>> result = parser.parse_args(cmd.split())
>>> result.action
'deploy'
>>> result.targets
['sneezy.example.com', 'sleepy.example.com']
>>> result.user
'skycaptain'

Пример автоматически сгенерированной справки парсера:

>>> parser.parse_args('-h'.split())

usage: manage_cloud.py [-h] -u USER
                       {deploy,start,stop} HOSTNAME [HOSTNAME ...]

Manage servers

positional arguments:
  {deploy,start,stop}   action on each target
  HOSTNAME              url for target machines

optional arguments:
  -h, --help            show this help message and exit
  -u USER, --user USER  login as user

Tested on Solaris and Linux

Особенно удобная возможность argparse – это возможность определять подпарсеры, каждый со своими шаблонами аргументов и справкой:

import argparse
parser = argparse.ArgumentParser(prog='HELM')
subparsers = parser.add_subparsers()

parser_l = subparsers.add_parser('launch', help='Launch Control')   # первая подгруппа
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',        # вторая подгруппа
                                 aliases=('steer', 'turn'))         # эквивалентные имена
parser_m.add_argument('-c', '--course', type=int, required=True)
parser_m.add_argument('-s', '--speed', type=int, default=0)
$ ./helm.py --help                         # справка верхнего уровня (запуск и перемещение)
$ ./helm.py launch --help                  # справка по параметрам запуска
$ ./helm.py launch --missiles              # задать missiles=True и torpedos=False
$ ./helm.py steer --course 180 --speed 5   # задать параметры движения

См. также

PEP 389 - Новый модуль разбора командной строки

PEP написан Стивеном Бетардом.

Переход с optparse на argparse – подробнее о различиях с optparse.

PEP 391: Конфигурация логирования на основе словарейPEP 391: Dictionary Based Configuration for Logging

Модуль logging предоставлял два вида конфигурации: один строится на вызовах функций для каждого параметра, другой – на внешнем файле в формате configparser. Эти варианты не давали гибкости для создания конфигураций из файлов JSON или YAML, а также не поддерживали инкрементальную настройку, необходимую для задания параметров логгера из командной строки.

Для поддержки более гибкого подхода модуль теперь предлагает logging.config.dictConfig() для задания конфигурации логирования с помощью обычных словарей Python. Параметры конфигурации включают форматтеры, обработчики, фильтры и логгеры. Вот рабочий пример словаря конфигурации:

{"version": 1,
 "formatters": {"brief": {"format": "%(levelname)-8s: %(name)-15s: %(message)s"},
                "full": {"format": "%(asctime)s %(name)-15s %(levelname)-8s %(message)s"}
                },
 "handlers": {"console": {
                   "class": "logging.StreamHandler",
                   "formatter": "brief",
                   "level": "INFO",
                   "stream": "ext://sys.stdout"},
              "console_priority": {
                   "class": "logging.StreamHandler",
                   "formatter": "full",
                   "level": "ERROR",
                   "stream": "ext://sys.stderr"}
              },
 "root": {"level": "DEBUG", "handlers": ["console", "console_priority"]}}

Если этот словарь сохранён в файле conf.json, его можно загрузить и вызвать следующим кодом:

>>> import json, logging.config
>>> with open('conf.json') as f:
...     conf = json.load(f)
...
>>> logging.config.dictConfig(conf)
>>> logging.info("Transaction completed normally")
INFO    : root           : Transaction completed normally
>>> logging.critical("Abnormal termination")
2011-02-17 11:14:36,694 root            CRITICAL Abnormal termination

См. также

PEP 391 – Конфигурация логирования на основе словарей

PEP написан Винаем Саджипом.

PEP 3148: Модуль concurrent.futuresPEP 3148: The concurrent.futures module

Код для создания параллельного выполнения и управления им собирается в новом пространстве имён верхнего уровня concurrent. Первый его компонент – пакет futures, предоставляющий единый высокоуровневый интерфейс для управления потоками и процессами.

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

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

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

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

Простой пример ThreadPoolExecutor – запуск четырёх параллельных потоков для копирования файлов:

import concurrent.futures, shutil
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as e:
    e.submit(shutil.copy, 'src1.txt', 'dest1.txt')
    e.submit(shutil.copy, 'src2.txt', 'dest2.txt')
    e.submit(shutil.copy, 'src3.txt', 'dest3.txt')
    e.submit(shutil.copy, 'src3.txt', 'dest4.txt')

См. также

PEP 3148 – Futures – асинхронное выполнение вычислений

PEP написан Брайаном Куинланом.

Код для параллельного чтения URL в потоках – пример использования потоков для параллельной загрузки нескольких веб-страниц.

Код для параллельного вычисления простых чисел – пример, демонстрирующий ProcessPoolExecutor.

PEP 3147: Директории репозитория PYCPEP 3147: PYC Repository Directories

Схема кэширования байт-кода Python в файлы .pyc плохо работала в средах с несколькими интерпретаторами Python. Если один интерпретатор встречал кэшированный файл, созданный другим, он перекомпилировал исходный код и перезаписывал кэш, теряя преимущества кэширования.

Проблема «pyc-войн» стала более заметной, поскольку в дистрибутивах Linux стало обычным делом поставлять несколько версий Python. Эти конфликты возникают и с альтернативными реализациями CPython, такими как Unladen Swallow.

Чтобы решить эту проблему, механизм импорта Python был расширен для использования разных имён файлов для каждого интерпретатора. Вместо того чтобы Python 3.2, Python 3.3 и Unladen Swallow конкурировали за файл с именем «mymodule.pyc», теперь они будут искать «mymodule.cpython-32.pyc», «mymodule.cpython-33.pyc» и «mymodule.unladen10.pyc». А чтобы все эти новые файлы не засоряли исходные каталоги, файлы pyc теперь собираются в каталог «__pycache__», расположенный внутри каталога пакета.

Помимо имён файлов и целевых каталогов, новая схема имеет несколько аспектов, видимых программисту:

  • Импортированные модули теперь имеют атрибут __cached__, который хранит имя фактически импортированного файла:

    >>> import collections
    >>> collections.__cached__
    'c:/py32/lib/__pycache__/collections.cpython-32.pyc'
    
  • Уникальный для каждого интерпретатора тег доступен из модуля imp:

    >>> import imp
    >>> imp.get_tag()
    'cpython-32'
    
  • Скрипты, пытающиеся определить имя исходного файла по импортированному файлу, теперь должны быть умнее. Просто удалить букву «c» из имени файла «.pyc» уже недостаточно. Вместо этого используйте новые функции из модуля imp:

    >>> imp.source_from_cache('c:/py32/lib/__pycache__/collections.cpython-32.pyc')
    'c:/py32/lib/collections.py'
    >>> imp.cache_from_source('c:/py32/lib/collections.py')
    'c:/py32/lib/__pycache__/collections.cpython-32.pyc'
    
  • Модули py_compile и compileall были обновлены, чтобы отразить новое соглашение об именовании и целевой каталог. Вызов из командной строки compileall получил новые опции: -i для указания списка файлов и каталогов для компиляции и -b, которая заставляет записывать файлы байт-кода в их прежнее расположение, а не в __pycache__.

  • Модуль importlib.abc обновлён новыми абстрактными базовыми классами для загрузки файлов байт-кода. Устаревшие ABC, PyLoader и PyPycLoader, объявлены устаревшими (в документацию включены инструкции по сохранению совместимости с Python 3.1).

См. также

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

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

PEP 3149: .so-файлы с тегом версии ABIPEP 3149: ABI Version Tagged .so Files

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

Общая директория называется «pyshared», а имена файлов различаются указанием реализации Python (например, CPython, PyPy, Jython и т.д.), номерами старшей и младшей версии, а также необязательными флагами сборки (например, «d» для отладки, «m» для pymalloc, «u» для wide-unicode). Для произвольного пакета «foo» при установке дистрибутивного пакета можно увидеть такие файлы:

/usr/share/pyshared/foo.cpython-32m.so
/usr/share/pyshared/foo.cpython-33md.so

В самом Python теги доступны через функции из модуля sysconfig:

>>> import sysconfig
>>> sysconfig.get_config_var('SOABI')       # найти тег версии
'cpython-32mu'
>>> sysconfig.get_config_var('EXT_SUFFIX')  # найти полное расширение имени файла
'.cpython-32mu.so'

См. также

PEP 3149 – файлы .so с тегами версии ABI

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

PEP 3333: Python Web Server Gateway Interface v1.0.1

Этот информационный PEP разъясняет, как в протоколе WSGI следует обрабатывать вопросы, связанные с байтами и текстом. Сложность в том, что в Python 3 со строками удобнее всего работать через тип str, хотя сам протокол HTTP ориентирован на байты.

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

Нативные строки всегда имеют тип str, но ограничены кодовыми точками от U+0000 до U+00FF, которые могут быть преобразованы в байты с использованием кодировки Latin-1. Эти строки используются для ключей и значений в словаре окружения, а также для заголовков и статусов ответов в функции start_response(). Они должны соответствовать RFC 2616 в отношении кодировки. То есть они должны быть либо символами ISO-8859-1, либо использовать кодировку MIME RFC 2047.

Для разработчиков, переносящих WSGI-приложения с Python 2, вот ключевые моменты:

  • Если приложение уже использовало строки для заголовков в Python 2, никаких изменений не требуется.

  • Если же приложение кодировало выходные заголовки или декодировало входные, то заголовки потребуется перекодировать в Latin-1. Например, выходной заголовок, закодированный в utf-8, использовал h.encode('utf-8'), теперь же необходимо преобразовать байты в нативные строки с помощью h.encode('utf-8').decode('latin-1').

  • Значения, возвращаемые приложением или отправляемые с помощью метода write(), должны быть байтовыми строками. Функция start_response() и environ должны использовать нативные строки. Их нельзя смешивать.

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

См. также

PEP 3333 – Python Web Server Gateway Interface v1.0.1

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

Прочие изменения языка Other Language Changes

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

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

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

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

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

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

    Теперь это разрешено. Помните, что цель (target) в предложении except очищается, поэтому этот код, который работал в Python 2.6, вызывал SyntaxError в Python 3.1, а теперь снова работает:

    def f():
        def print_error():
            print(e)
        try:
            something
        except Exception as e:
            print_error()
            # неявное "del e" здесь
    

    (См. bpo-4617.)

  • Типы структурных последовательностей теперь являются подклассами кортежа. Это означает, что C-структуры, такие как возвращаемые os.stat(), time.gmtime() и sys.version_info, теперь работают как именованный кортеж и могут использоваться с функциями и методами, ожидающими кортеж в качестве аргумента. Это большой шаг вперёд в придании 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 и реализовано Benjamin Peterson в bpo-8413.)

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

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

    (Предложено Barry Warsaw и реализовано Philip Jenvey в bpo-7301.)

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

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

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

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

    (Добавлено Antoine Pitrou и Georg Brandl в bpo-10093 и bpo-477863.)

  • Объекты range теперь поддерживают методы index и count. Это часть усилий по расширению реализации collections.Sequence абстрактного базового класса на большее количество объектов. В результате язык получит более единообразный API. Кроме того, объекты range теперь поддерживают срезы и отрицательные индексы, даже со значениями, превышающими sys.maxsize. Это делает range более совместимым со списками:

    >>> range(0, 100, 2).count(10)
    1
    >>> range(0, 100, 2).index(10)
    5
    >>> range(0, 100, 2)[5]
    10
    >>> range(0, 100, 2)[0:5]
    range(0, 10, 2)
    

    (Вклад Daniel Stutzbach в bpo-9213, Alexander Belopolsky в bpo-2690 и Nick Coghlan в bpo-10889.)

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

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

    (См. bpo-10518.)

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

(Потребовало значительной работы от Victor Stinner в bpo-9425.)

Новые, улучшенные и устаревшие модулиNew, Improved, and Deprecated Modules

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

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

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

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

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

email

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

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

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

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

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

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

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

(Предложено и реализовано R. David Murray, bpo-4661 и bpo-10321.)

elementtree

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

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

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

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

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

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

(Авторы: Florent Xicluna и Fredrik Lundh, 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)        # кэшированный поиск
    

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

    >>> get_phone_number.cache_info()
    CacheInfo(hits=4805, misses=980, maxsize=300, currsize=300)
    

    Если таблица phonelist обновляется, устаревшее содержимое кеша можно очистить с помощью:

    >>> get_phone_number.cache_clear()
    

    (Автор: Raymond Hettinger с использованием идей дизайна от Jim Baker, Miki Tebeka и Nick Coghlan; см. recipe 498245, recipe 577479, bpo-10586 и bpo-10593.)

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

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

    >>> get_phone_number = get_phone_number.__wrapped__    # некэшированная функция
    

    (Авторы: Nick Coghlan и Terrence Cole; bpo-9567, bpo-3445 и bpo-8814.)

  • Чтобы упростить написание классов с методами полного сравнения, новый декоратор @functools.total_ordering будет использовать существующие методы равенства и неравенства для заполнения остальных методов.

    Например, указав __eq__ и __lt__, можно позволить @~functools.total_ordering заполнить __le__, __gt__ и __ge__:

    @total_ordering
    class Student:
        def __eq__(self, other):
            return ((self.lastname.lower(), self.firstname.lower()) ==
                    (other.lastname.lower(), other.firstname.lower()))
    
        def __lt__(self, other):
            return ((self.lastname.lower(), self.firstname.lower()) <
                    (other.lastname.lower(), other.firstname.lower()))
    

    С помощью декоратора total_ordering остальные методы сравнения заполняются автоматически.

    (Автор: Raymond Hettinger.)

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

    >>> # порядок сортировки с учётом локали
    >>> sorted(iterable, key=cmp_to_key(locale.strcoll))
    

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

    (Автор: Raymond Hettinger.)

itertools

  • Модуль itertools содержит новую функцию accumulate(), созданную по образцу оператора scan из APL и функции accumulate из Numpy:

    >>> from itertools import accumulate
    >>> list(accumulate([8, 2, 50]))
    [8, 10, 60]
    
    >>> prob_dist = [0.1, 0.4, 0.2, 0.3]
    >>> list(accumulate(prob_dist))      # кумулятивное распределение вероятностей
    [0.1, 0.5, 0.7, 1.0]
    

    Пример использования accumulate() см. в примерах для модуля random.

    (Автор: Raymond Hettinger с учётом предложений по дизайну от Mark Dickinson.)

collections

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

    >>> from collections import Counter
    >>> tally = Counter(dogs=5, cats=3)
    >>> tally -= Counter(dogs=2, cats=8)    # насыщающее вычитание
    >>> tally
    Counter({'dogs': 3})
    
    >>> tally = Counter(dogs=5, cats=3)
    >>> tally.subtract(dogs=2, cats=8)      # обычное вычитание
    >>> tally
    Counter({'dogs': 3, 'cats': -5})
    

    (Автор: Raymond Hettinger.)

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

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

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

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

    (Автор: Raymond Hettinger.)

  • У класса 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'])
    

    (Автор: Raymond Hettinger.)

threading

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

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

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

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

from threading import Barrier, Thread

def get_votes(site):
    ballots = conduct_election(site)
    all_polls_closed.wait()        # не подсчитывать, пока все голосования не закрыты
    totals = summarize(ballots)
    publish(site, totals)

all_polls_closed = Barrier(len(sites))
for site in sites:
    Thread(target=get_votes, args=(site,)).start()

В этом примере барьер обеспечивает соблюдение правила, согласно которому голоса не могут быть подсчитаны на любом избирательном участке, пока все участки не закроются. Обратите внимание, что решение с барьером похоже на решение с threading.Thread.join(), но после пересечения точки барьера потоки остаются живыми и продолжают работать (подсчитывать бюллетени).

Если какая-либо из предшествующих задач может зависнуть или задержаться, барьер можно создать с необязательным параметром тайм-аут. Тогда, если период ожидания истекает до того, как все предшествующие задачи достигнут точки барьера, все ожидающие потоки освобождаются и возбуждается исключение BrokenBarrierError:

def get_votes(site):
    ballots = conduct_election(site)
    try:
        all_polls_closed.wait(timeout=midnight - time.now())
    except BrokenBarrierError:
        lockbox = seal_ballots(ballots)
        queue.put(lockbox)
    else:
        totals = summarize(ballots)
        publish(site, totals)

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

Смотрите Barrier Synchronization Patterns для получения дополнительных примеров использования барьеров в параллельных вычислениях. Также простое, но подробное объяснение барьеров даётся в The Little Book of Semaphores, раздел 3.6.

(Автор: Kristján Valur Jónsson, рецензирование API: Jeffrey Yasskin, в bpo-8777.)

datetime and time

  • В модуле datetime появился новый тип timezone, который реализует интерфейс tzinfo, возвращая фиксированное смещение UTC и название часового пояса. Это упрощает создание объектов datetime с учётом часового пояса:

    >>> import datetime as dt
    
    >>> dt.datetime.now(dt.timezone.utc)
    datetime.datetime(2010, 12, 8, 21, 4, 2, 923754, tzinfo=datetime.timezone.utc)
    
    >>> dt.datetime.strptime("01/01/2000 12:00 +0000", "%m/%d/%Y %H:%M %z")
    datetime.datetime(2000, 1, 1, 12, 0, tzinfo=datetime.timezone.utc)
    
  • Кроме того, объекты timedelta теперь можно умножать на float и делить на float и int. А объекты timedelta теперь можно делить друг на друга.

  • Метод datetime.date.strftime() больше не ограничен годами после 1900. Новый поддерживаемый диапазон лет – от 1000 до 9999 включительно.

  • Всякий раз, когда в кортеже времени используется двузначный год, его интерпретация определяется time.accept2dyear. По умолчанию используется True, что означает, что для двузначного года век определяется по правилам POSIX, регламентирующим формат %y strptime.

    Начиная с Py3.2, использование эвристики угадывания века будет вызывать предупреждение DeprecationWarning. Вместо этого рекомендуется установить time.accept2dyear в False, чтобы можно было использовать большие диапазоны дат без угадывания:

    >>> import time, warnings
    >>> warnings.resetwarnings()      # удалить фильтры предупреждений по умолчанию
    
    >>> time.accept2dyear = True      # угадать, означает ли 11 число 11 или 2011
    >>> time.asctime((11, 1, 1, 12, 34, 56, 4, 1, 0))
    Warning (from warnings module):
      ...
    DeprecationWarning: Century info guessed for a 2-digit year.
    'Fri Jan  1 12:34:56 2011'
    
    >>> time.accept2dyear = False     # использовать полный диапазон допустимых дат
    >>> time.asctime((11, 1, 1, 12, 34, 56, 4, 1, 0))
    'Fri Jan  1 12:34:56 11'
    

    Несколько функций теперь имеют значительно расширенные диапазоны дат. Когда time.accept2dyear имеет значение false, функция time.asctime() принимает любой год, помещающийся в int в C, а функции time.mktime() и time.strftime() принимают полный диапазон, поддерживаемый соответствующими функциями операционной системы.

(Авторы: Alexander Belopolsky и Victor Stinner в bpo-1289118, bpo-5094, bpo-6641, bpo-2706, bpo-1777412, bpo-8013 и bpo-10827.)

math

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

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

>>> 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)   # более точный способ вычисления e**x-1 для малых x
0.013765762467652909

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

>>> from math import erf, erfc, sqrt
>>> erf(1.0/sqrt(2.0))   # доля нормального распределения в пределах одного стандартного отклонения
0.682689492137086
>>> erfc(1.0/sqrt(2.0))  # доля нормального распределения за пределами одного стандартного отклонения
0.31731050786291404
>>> erf(1.0/sqrt(2.0)) + erfc(1.0/sqrt(2.0))
1.0

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

>>> from math import gamma, lgamma
>>> gamma(7.0)           # шесть факториал
720.0
>>> lgamma(801.0)        # логарифм факториала 800
4551.950730698041

(Автор: Mark Dickinson.)

abc

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

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

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

(Патч предоставлен Daniel Urban; 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 получил новый декоратор @~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

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

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

Функция настройки logging.basicConfig() получила аргумент style для поддержки трёх различных типов форматирования строк. По умолчанию он равен «%» для традиционного форматирования через %, может быть установлен в «{» для нового стиля str.format() или в «$» для форматирования в стиле оболочки, предоставляемого string.Template. Следующие три конфигурации эквивалентны:

>>> from logging import basicConfig
>>> basicConfig(style='%', format="%(name)s -> %(levelname)s: %(message)s")
>>> basicConfig(style='{', format="{name} -> {levelname} {message}")
>>> basicConfig(style='$', format="$name -> $levelname: $message")

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

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

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

csv

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

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

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

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

contextlib

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

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

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

Например, иногда полезно обернуть функции или группы операторов логгером, который может отслеживать время входа и время выхода. Вместо написания как декоратора функций, так и менеджера контекста для этой задачи, @~contextlib.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.)

decimal and fractions

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

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

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

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

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

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

(Авторы: Mark Dickinson и Raymond Hettinger.)

ftp

Класс ftplib.FTP теперь поддерживает протокол управления контекстом для безусловного поглощения исключений socket.error и закрытия FTP-соединения по завершении:

>>> from ftplib import FTP
>>> with FTP("ftp1.at.proftpd.org") as ftp:
        ftp.login()
        ftp.dir()

'230 Anonymous login ok, restrictions apply.'
dr-xr-xr-x   9 ftp      ftp           154 May  6 10:43 .
dr-xr-xr-x   9 ftp      ftp           154 May  6 10:43 ..
dr-xr-xr-x   5 ftp      ftp          4096 May  6 10:43 CentOS
dr-xr-xr-x   3 ftp      ftp            18 Jul 10  2008 Fedora

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

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

(Авторы: Tarek Ziadé и Giampaolo Rodolà в bpo-4972, и Georg Brandl в bpo-8046 и bpo-1286.)

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

(Автор: Giampaolo Rodolà; bpo-8806.)

popen

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

(Авторы: Antoine Pitrou и Brian Curtin в bpo-7461 и bpo-10554.)

select

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

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

(Доступно в системах Unix. Патч от Sébastien Sablé в bpo-9862)

gzip and zipfile

gzip.GzipFile теперь реализует io.BufferedIOBase абстрактный базовый класс (за исключением 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()                        # преобразовать в utf-8
>>> len(b)
89
>>> c = gzip.compress(b)
>>> len(c)
77
>>> gzip.decompress(c).decode()[:42]      # распаковать и преобразовать в текст
'Three shall be the number thou shalt count'

(Авторы: Anand B. Pillai в bpo-3488; и Antoine Pitrou, Nir Aides и Brian Curtin в bpo-9962, bpo-1675951, bpo-7471 и bpo-2846.)

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

(Патч предоставлен Nir Aides в bpo-7610.)

tarfile

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

Новая опция filter заменяет старый, менее гибкий параметр exclude, который теперь устарел. Если указан, дополнительный параметр filter должен быть именованным аргументом. Предоставленная пользователем функция фильтра принимает объект TarInfo и возвращает обновлённый объект TarInfo, или, если нужно исключить файл, функция может вернуть None:

>>> import tarfile, glob

>>> def myfilter(tarinfo):
...     if tarinfo.isfile():             # сохранять только реальные файлы
...         tarinfo.uname = 'monty'      # отредактировать имя пользователя
...         return tarinfo

>>> with tarfile.open(name='myarchive.tar.gz', mode='w:gz') as tf:
...     for filename in glob.glob('*.txt'):
...         tf.add(filename, filter=myfilter)
...     tf.list()
-rw-r--r-- monty/501        902 2011-01-26 17:59:11 annotations.txt
-rw-r--r-- monty/501        123 2011-01-26 17:59:11 general_questions.txt
-rw-r--r-- monty/501       3514 2011-01-26 17:59:11 prion.txt
-rw-r--r-- monty/501        124 2011-01-26 17:59:11 py_todo.txt
-rw-r--r-- monty/501       1399 2011-01-26 17:59:11 semaphore_notes.txt

(Предложено Tarek Ziadé и реализовано Lars Gustäbel в 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'}

(Предложено Carl Chenet в 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.

(Автор: Victor Stinner.)

shutil

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

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

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

(Автор: Tarek Ziadé.)

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

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

>>> import shutil, pprint

>>> os.chdir('mydata')  # перейти в каталог исходного кода
>>> f = shutil.make_archive('/var/backup/mydata',
...                         'zip')      # архивировать текущий каталог
>>> f                                   # показать имя архива
'/var/backup/mydata.zip'
>>> os.chdir('tmp')                     # перейти к распаковке
>>> shutil.unpack_archive('/var/backup/mydata.zip')  # восстановить данные

>>> pprint.pprint(shutil.get_archive_formats())  # отобразить известные форматы
[('bztar', "bzip2'ed tar-file"),
 ('gztar', "gzip'ed tar-file"),
 ('tar', 'uncompressed tar file'),
 ('zip', 'ZIP file')]

>>> shutil.register_archive_format(     # зарегистрировать новый формат архива
...     name='xz',
...     function=xz.compress,           # вызываемая функция архивирования
...     extra_args=[('level', 8)],      # аргументы функции
...     description='xz compression'
... )

(Автор: Tarek Ziadé.)

sqlite3

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

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

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

(Авторы: R. David Murray и Shashwat Anand; 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(), который переводит сокет в закрытое состояние, не закрывая фактически базовый файловый дескриптор. Последний затем можно использовать для других целей. (Добавлено Antoine Pitrou; bpo-8524.)

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

ssl

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

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

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

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

  • При компоновке с последними версиями OpenSSL модуль ssl теперь поддерживает расширение Server Name Indication протокола TLS, что позволяет размещать несколько «виртуальных хостов» с разными сертификатами на одном IP-порту. Это расширение поддерживается только в клиентском режиме и активируется передачей аргумента server_hostname в ssl.SSLContext.wrap_socket().

  • В модуль ssl добавлены различные опции, такие как OP_NO_SSLv2, которая отключает небезопасный и устаревший протокол SSLv2.

  • Расширение теперь загружает все шифры и алгоритмы дайджестов OpenSSL. Если некоторые SSL-сертификаты не удаётся проверить, они сообщаются как ошибка «неизвестный алгоритм».

  • Версия используемого OpenSSL теперь доступна через атрибуты модуля ssl.OPENSSL_VERSION (строка), ssl.OPENSSL_VERSION_INFO (кортеж из 5 элементов) и ssl.OPENSSL_VERSION_NUMBER (целое число).

(Предложено Антуаном Питру в 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.)

сертификатыcertificates

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-соединение.

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

Метод request() у объектов соединения допускал необязательный аргумент body, чтобы для содержимого запроса можно было использовать файловый объект. Удобно, что аргумент body теперь также принимает итерируемый объект при условии, что он содержит явный заголовок 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
    

    (Предложено Michael Foord.)

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

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

    (Предложено Michael Foord.)

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

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

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

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

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

    (Автор: Raymond Hettinger.)

  • Одна из основных особенностей модуля unittest – стремление выдавать содержательные диагностические сообщения при сбое теста. По возможности сбой записывается вместе с diff вывода. Это особенно полезно при анализе журналов неудачных тестовых запусков. Однако, поскольку diff может быть объёмным, появился новый атрибут maxDiff, задающий максимальную длину отображаемого diff.

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

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

    (Предложено Raymond Hettinger; реализовано Ezio Melotti.)

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

    Старое имя

    Предпочтительное имя

    assert_()

    assertTrue()

    assertEquals()

    assertEqual()

    assertNotEquals()

    assertNotEqual()

    assertAlmostEquals()

    assertAlmostEqual()

    assertNotAlmostEquals()

    assertNotAlmostEqual()

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

    (Предложено Ezio Melotti; bpo-9424.)

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

    (Автор: Raymond Hettinger.)

random

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

(Предложено Raymond Hettinger; bpo-9025.)

poplib

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

(Предложено Giampaolo Rodolà; bpo-8807.)

asyncore

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

(Предложено Giampaolo Rodolà; bpo-6706.)

tempfile

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

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

(Предложено Neil Schemenauer и Nick Coghlan; bpo-5178.)

inspect

  • Модуль inspect содержит новую функцию getgeneratorstate() для простого определения текущего состояния генератора-итератора:

    >>> from inspect import getgeneratorstate
    >>> def gen():
    ...     yield 'demo'
    ...
    >>> g = gen()
    >>> getgeneratorstate(g)
    'GEN_CREATED'
    >>> next(g)
    'demo'
    >>> getgeneratorstate(g)
    'GEN_SUSPENDED'
    >>> next(g, None)
    >>> getgeneratorstate(g)
    'GEN_CLOSED'
    

    (Предложено Rodolpho Eckhardt и Nick Coghlan; 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>
    

(Предложено Michael Foord.)

pydoc

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

$ pydoc3.2 -b

(Предложено Ron Adam; 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, и позволяют самому увидеть, что делает синтаксис языка «под капотом».

(Предложено Nick Coghlan; bpo-9147.)

dbm

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

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

ctypes

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

site

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

  • getsitepackages() выводит список всех глобальных каталогов site-packages.

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

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

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

Удобно, что часть функциональности site доступна напрямую из командной строки:

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

(Добавлено Тареком Зиаде в 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. Поддержка inline-комментариев теперь по умолчанию отключена, а дубликаты секций или опций не допускаются в одном источнике конфигурации.

Парсеры конфигураций получили новый API на основе протокола отображения:

>>> parser = ConfigParser()
>>> parser.read_string("""
... [DEFAULT]
... location = upper left
... visible = yes
... editable = no
... color = blue
...
... [main]
... title = Main Menu
... color = green
...
... [options]
... title = Options
... """)
>>> parser['main']['color']
'green'
>>> parser['main']['editable']
'no'
>>> section = parser['options']
>>> section['title']
'Options'
>>> section['title'] = 'Options (editable: %(editable)s)'
>>> section['title']
'Options (editable: no)'

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

Структура INI-файла, принимаемая парсерами конфигураций, теперь может быть настроена. Пользователи могут задавать альтернативные разделители опция/значение и префиксы комментариев, изменять имя секции DEFAULT или переключать синтаксис интерполяции.

Поддерживается подключаемая интерполяция, включая дополнительный обработчик интерполяции ExtendedInterpolation:

>>> parser = ConfigParser(interpolation=ExtendedInterpolation())
>>> parser.read_dict({'buildout': {'directory': '/home/ambv/zope9'},
...                   'custom': {'prefix': '/usr/local'}})
>>> parser.read_string("""
... [buildout]
... parts =
...   zope9
...   instance
... find-links =
...   ${buildout:directory}/downloads/dist
...
... [zope9]
... recipe = plone.recipe.zope9install
... location = /opt/zope
...
... [instance]
... recipe = plone.recipe.zope9instance
... zope9-location = ${zope9:location}
... zope-conf = ${custom:prefix}/etc/zope.conf
... """)
>>> parser['buildout']['find-links']
'\n/home/ambv/zope9/downloads/dist'
>>> parser['instance']['zope-conf']
'/usr/local/etc/zope.conf'
>>> instance = parser['instance']
>>> instance['zope-conf']
'/usr/local/etc/zope.conf'
>>> instance['zope9-location']
'/opt/zope'

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

(Все изменения предоставлены Łukasz Langa.)

urllib.parse

Для модуля urllib.parse был сделан ряд улучшений удобства использования.

Функция urlparse() теперь поддерживает адреса IPv6, как описано в RFC 2732:

>>> import urllib.parse
>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/')
ParseResult(scheme='http',
            netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]',
            path='/foo/',
            params='',
            query='',
            fragment='')

Функция urldefrag() теперь возвращает именованный кортеж:

>>> r = urllib.parse.urldefrag('http://python.org/about/#target')
>>> r
DefragResult(url='http://python.org/about/', fragment='target')
>>> r[0]
'http://python.org/about/'
>>> r.fragment
'target'

Кроме того, функция urlencode() теперь стала гораздо более гибкой, принимая аргумент query как строкового, так и байтового типа. Если это строка, то параметры safe, encoding и error передаются в quote_plus() для кодирования:

>>> urllib.parse.urlencode([
...      ('type', 'telenovela'),
...      ('name', '¿Dónde Está Elisa?')],
...      encoding='latin-1')
'type=telenovela&name=%BFD%F3nde+Est%E1+Elisa%3F'

Как подробно описано в Parsing ASCII Encoded Bytes, все функции urllib.parse теперь принимают на вход ASCII-кодированные байтовые строки, при условии, что они не смешиваются с обычными строками. Если в качестве параметров указаны ASCII-кодированные байтовые строки, возвращаемые типы также будут ASCII-кодированными байтовыми строками:

>>> urllib.parse.urlparse(b'http://www.python.org:80/about/')
ParseResultBytes(scheme=b'http', netloc=b'www.python.org:80',
                 path=b'/about/', params=b'', query=b'', fragment=b'')

(Работа Nick Coghlan, Dan Mahn и Senthil Kumaran в bpo-2987, bpo-5468 и bpo-9873.)

mailbox

Благодаря согласованным усилиям R. David Murray, модуль mailbox был исправлен для Python 3.2. Сложность заключалась в том, что mailbox изначально был спроектирован с текстовым интерфейсом, но email-сообщения лучше представлять с помощью bytes, поскольку различные части сообщения могут иметь разные кодировки.

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

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

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

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

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

(Предоставлено R. David Murray, при участии Steffen Daode Nurpmeso и начального патча от Victor Stinner в bpo-9124.)

turtledemo

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

$ python -m turtledemo

(Перенесён из каталога Demo Alexander Belopolsky в bpo-10199.)

МногопоточностьMulti-threading

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

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

    (Предоставлено Antoine Pitrou.)

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

  • Аналогично, threading.Semaphore.acquire() также получил аргумент timeout. (Предоставлено Torsten Landschoff; bpo-850728.)

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

ОптимизацииOptimizations

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

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

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

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

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

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

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

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

    (Патч от Дэниела Штуцбаха в bpo-9915.)

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

    (Предоставлено Антуаном Питру в 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 от Эндрю Шаафа). Функция operator.attrgetter() была ускорена (bpo-10160 от Христоса Георгиу). И ConfigParser загружает многострочные аргументы немного быстрее (bpo-7113 от Лукаша Ланги).

ЮникодUnicode

Python был обновлён до Unicode 6.0.0. Обновление стандарта добавляет более 2000 новых символов, включая эмодзи, которые важны для мобильных телефонов.

Кроме того, обновлённый стандарт изменил свойства символов для двух символов каннада (U+0CF1, U+0CF2) и одного числового символа New Tai Lue (U+19DA), сделав первые допустимыми для использования в идентификаторах, а последний – недопустимым. Подробнее см. Unicode Character Database Changes.

КодекиCodecs

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

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

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

Для эмуляции кодировки MBCS Python 3.1 выберите обработчик 'ignore' для декодирования и 'replace' для кодирования.

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

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

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

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

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

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

    Исходный код Lib/functools.py.

    (Автор: Raymond Hettinger; см. обоснование.)

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

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

    (Автор: Alexander Belopolsky; bpo-9528.)

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

    (Автор: Georg Brandl; bpo-7962.)

IDLE

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

    (Автор: Raymond Hettinger; bpo-5150.)

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

    (Авторы: Kevin Walzer, Ned Deily и Ronald Oussoren; bpo-6075.)

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

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

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

Чтобы научиться пользоваться новой системой управления версиями, см. «Быстрый старт» или «Руководство по рабочим процессам Mercurial».

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

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

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

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

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

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

    (Автор: Antoine Pitrou; bpo-9203.)

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

    (Автор: Amaury Forgeot D’Arc; bpo-9210.)

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

    (Предложено Raymond Hettinger, реализовано Benjamin Peterson; bpo-9778.)

  • Новый макрос Py_VA_COPY копирует состояние списка аргументов переменной длины. Он эквивалентен va_copy из C99, но доступен на всех платформах 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 те же возможности самодокументирования, что и их аналогам на чистом Python (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.2Porting to Python 3.2

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

  • Модуль configparser претерпел ряд исправлений. Самое существенное изменение – замена старого класса ConfigParser на давно рекомендуемую альтернативу SafeConfigParser. Кроме того, имеется ряд более мелких несовместимостей:

    • Синтаксис интерполяции теперь проверяется при операциях get() и set(). В схеме интерполяции по умолчанию допустимы только два токена с символом процента: %(name)s и %% (последний – экранированный знак процента).

    • Методы set() и add_section() теперь проверяют, что значения являются строками. Раньше неподдерживаемые типы могли быть вставлены непреднамеренно.

    • Повторяющиеся секции или параметры из одного источника теперь вызывают DuplicateSectionError или DuplicateOptionError. Раньше дубликаты молча перезаписывали предыдущую запись.

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

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

    • "" теперь является допустимым значением и больше не преобразуется автоматически в пустую строку. Для пустых строк используйте "option =" в строке.

  • Модуль nntplib был существенно переработан, поэтому его API часто несовместимы с API версии 3.1.

  • Объекты bytearray больше нельзя использовать в качестве имён файлов; вместо этого их следует преобразовывать в bytes.

  • array.tostring() и array.fromstring() переименованы в array.tobytes() и array.frombytes() для ясности. Старые имена объявлены устаревшими. (См. 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 с промежуточными таблицами перевода соответствующего типа.

    (Предложено Georg Brandl; 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)
    

    (Предложено Georg Brandl и Mattias Brändström; appspot issue 53094.)

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

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

    (Обнаружено David Beazley, исправлено Victor Stinner; bpo-10783.)

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

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

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

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

    (Предложено Antoine Pitrou, 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().