Что нового в Python 2.5

Автор:А.М. Кухлинг

В этой статье объясняются новые возможности Python 2.5. Окончательный релиз Python 2.5 запланирован на август 2006 г.; PEP 356 определяет запланированный график релиза.

Изменения в Python 2.5 представляют собой интересное сочетание усовершенствований языка и библиотеки. Я думаю, что улучшения в библиотеке будут более важны для сообщества пользователей Python, потому что было добавлено несколько широко полезных пакетов. Новые модули включают ElementTree для обработки XML (xml.etree), модуль базы данных SQLite (sqlite) и модуль ctypes для вызова функций C.

Языковые изменения имеют среднее значение. Были добавлены некоторые приятные новые функции, но большинство из них не являются функциями, которые вы будете использовать каждый день. Наконец, в язык были добавлены условные выражения с использованием нового синтаксиса; см. раздел PEP 308: условные выражения. Новый оператор with упростит написание кода очистки (раздел PEP 343: Оператор with). Теперь значения можно передавать в генераторы (раздел PEP 342: Новые функции генератора). Импорт теперь виден как абсолютный или относительный (раздел PEP 328: Абсолютный и относительный импорт). Некоторые крайние случаи обработки исключений обрабатываются лучше (раздел PEP 341: Унифицированный try/except/finally). Все данные улучшения имеют смысл, но они являются улучшениями той или иной языковой функции; ни один из них не является широкой модификацией семантики Python.

Помимо языковых и библиотечных дополнений, в исходном дереве были внесены другие улучшения и исправления. Поиск в журналах изменений SVN показывает, что между Python 2.4 и 2.5 было применено 353 исправления и исправлено 458 ошибок. (Обе цифры, вероятно, занижены)

Данная статья не претендует на полное описание новых возможностей; вместо этого кратко представлены изменения с использованием полезных примеров. Для получения полной информации вы всегда должны обращаться к документации по Python 2.5 по адресу. Если вы хотите понять полную реализацию и обоснование дизайна, обратитесь к PEP для новой функции.

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

PEP 308: условные выражения

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

if condition:
    x = true_value
else:
    x = false_value

Были бесконечные утомительные обсуждения синтаксиса как на python-dev, так и на comp.lang.python. Было даже проведено голосование, подтвердившее, что большинство избирателей хотели условных выражений в той или иной форме, но не было синтаксиса, предпочитаемого явным большинством. Кандидаты включали C cond ? true_v : false_v, if cond then true_v else false_v и 16 других вариантов.

Гвидо ван Россумом в конце концов выбрал неожиданный синтаксис:

x = true_value if condition else false_value

Вычисление по-прежнему ленивое, как и в существующих логических выражениях, поэтому порядок вычислений немного меняется. Выражение condition в середине вычисляется первым, а выражение true_value вычисляется, только если условие было истинным. Точно так же выражение false_value вычисляется только в том случае, если условие ложно.

Данный синтаксис может показаться странным и обратным; почему условие идет в середине выражения, а не в начале, как в C c ? x : y? Решение было проверено путём применения нового синтаксиса к модулям в стандартной библиотеке и просмотра того, как читается получившийся код. Во многих случаях, когда используется условное выражение, одно значение кажется «общим случаем», а другое значение — «исключительным случаем», используемым только в более редких случаях, когда условие не выполняется. Условный синтаксис делает данный шаблон немного более очевидным:

contents = ((doc + '\n') if doc else '')

Я прочитал приведенное выше утверждение как означающее «здесь contents обычно присваивается значение doc+'\n'; иногда doc пуст, и в этом особом случае возвращается пустая строка». Я сомневаюсь, что буду очень часто использовать условные выражения там, где нет четкого общего и необычного случая.

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

# Первая версия -- без скобок
level = 1 if logging else 0

# Второй вариант -- со скобками
level = (1 if logging else 0)

В первой версии, я думаю, читатель мог бы сгруппировать оператор в «level = 1», «если logging», «иначе 0» и подумать, что условие решает, выполняется ли присвоение level. Второй вариант, на мой взгляд, читается лучше, потому что дает понять, что присваивание выполняется всегда и выбор делается между двумя значениями.

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

См.также

PEP 308 — Условные выражения
PEP, написанный Гвидо ван Россумом и Рэймондом Д. Хеттингером; реализован Томасом Воутерс.

PEP 309: Приложение частичной функции

Модуль functools содержит инструменты для функционального программирования.

Одним из полезных инструментов в этом модуле является функция partial(). Для программ, написанных в функциональном стиле, вам иногда может понадобиться создать варианты существующих функций с заполненными некоторыми параметрами. Рассмотрим функцию Python f(a, b, c); вы можете создать новую функцию g(b, c), эквивалентную f(1, b, c). Это называется «частичным применением функций».

partial() принимает аргументы (function, arg1, arg2, ... kwarg1=value1, kwarg2=value2). Результирующий объект доступен для вызова, поэтому вы можете просто вызвать его, чтобы вызвать function с заполненными аргументами.

Вот небольшой, но реалистичный пример:

import functools

def log (message, subsystem):
    "Записать содержимое 'message' в указанную подсистему."
    print '%s: %s' % (subsystem, message)
    ...

server_log = functools.partial(log, subsystem='server')
server_log('Unable to open socket')

Вот ещё один пример из программы, использующей PyGTK. Здесь контекстно-зависимое всплывающее меню строится динамически. Обратный вызов, предоставленный для параметра меню, является частично примененной версией метода open_item(), где был предоставлен первый аргумент.

...
class Application:
    def open_item(self, path):
       ...
    def init (self):
        open_func = functools.partial(self.open_item, item_path)
        popup_menu.append( ("Open", open_func, 1) )

Ещё одна функция в модуле functools — это функция update_wrapper(wrapper, wrapped), которая помогает писать корректные декораторы. update_wrapper() копирует атрибут name, module и docstring в функцию-оболочку, чтобы облегчить понимание обратной трассировки внутри функции-оболочки. Например, вы можете написать:

def my_decorator(f):
    def wrapper(*args, **kwds):
        print 'Calling decorated function'
        return f(*args, **kwds)
    functools.update_wrapper(wrapper, f)
    return wrapper

wraps() — это декоратор, который можно использовать внутри ваших собственных декораторов для копирования информации обернутой функции. Альтернативной версией предыдущего примера будет:

def my_decorator(f):
    @functools.wraps(f)
    def wrapper(*args, **kwds):
        print 'Calling decorated function'
        return f(*args, **kwds)
    return wrapper

См.также

PEP 309 — Приложение с частичной функциональностью
PEP, предложенный и написанный Питером Харрисом; реализован Хе-Шик Чанг и Ник Коглана с адаптацией Рэймонда Хеттингера.

PEP 314: Метаданные для программных пакетов Python v1.1

В Distutils была добавлена некоторая поддержка простых зависимостей. Функция setup() теперь имеет ключевые параметры requires, provides и obsoletes. При сборке исходного дистрибутива с помощью команды sdist информация о зависимостях будет записана в файл PKG-INFO.

Другой новый ключевой параметр — download_url, который должен быть установлен на URL-адрес исходного кода пакета. Это означает, что теперь можно найти запись в указателе пакетов, определить зависимости для пакета и загрузить необходимые пакеты.

VERSION = '1.0'
setup(name='PyPackage',
      version=VERSION,
      requires=['numarray', 'zlib (>=1.1.4)'],
      obsoletes=['OldPackage']
      download_url=('http://www.example.com/pypackage/dist/pkg-%s.tar.gz'
                    % VERSION),
     )

Ещё одно новое усовершенствование индекса пакетов Python на https://pypi.org — это сохранение исходных и двоичных архивов для пакета. Новая команда upload Distutils загрузит пакет в репозиторий.

Перед загрузкой пакета вы должны иметь возможность собрать дистрибутив с помощью команды sdist Distutils. Как только это сработает, вы можете запустить python setup.py upload, чтобы добавить свой пакет в архив PyPI. При желании вы можете подписать пакет GPG, указав параметры --sign и --identity.

Загрузку пакетов реализовали Мартин фон Лёвис и Ричард Джонс.

См.также

PEP 314 — метаданные для программных пакетов Python v1.1
PEP, предложенный и написанный А.М. Кухлинг, Ричард Джонс и Фред Дрейк; реализованный Ричардом Джонсом и Фредом Дрейком.

PEP 328: Абсолютный и относительный импорт

Более простая часть PEP 328 была реализована в Python 2.4: теперь можно было использовать круглые скобки для заключения имён, импортированных из модуля с помощью оператора from ... import ..., что упростило импорт множества разных имён.

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

Допустим, у вас есть такой каталог пакетов:

pkg/
pkg/__init__.py
pkg/main.py
pkg/string.py

Это определяет пакет с именем pkg, содержащий подмодули pkg.main и pkg.string.

Рассмотрим код в модуле main.py. Что произойдет, если он выполнит оператор import string? В Python 2.4 и более ранних версиях он сначала просматривает каталог пакета для выполнения относительного импорта, находит pkg/string.py, импортирует содержимое этого файла как модуль pkg.string, и данный модуль привязан к имени string в пространстве имён модуля pkg.main.

Это нормально, если pkg.string был тем, что вы хотели. Но что, если вам нужен стандартный модуль Python string? Нет простого способа игнорировать pkg.string и искать стандартный модуль; вообще надо было смотреть содержимое sys.modules, что немного нечисто. Пакет py.std от Holger Krekel обеспечивает более аккуратный способ выполнения импорта из стандартной библиотеки import py; py.std.string.join(), но данный пакет доступен не во всех установках Python.

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

В Python 2.5 вы можете переключить поведение import на абсолютный импорт с помощью директивы from __future__ import absolute_import. Это поведение абсолютного импорта станет поведением по умолчанию в будущей версии (вероятно, Python 2.7). Если по умолчанию используется абсолютный импорт, import string всегда будет находить версию стандартной библиотеки. Предполагается, что пользователи должны начать использовать абсолютный импорт как можно чаще, поэтому предпочтительнее начинать писать from pkg import string в своём коде.

Относительный импорт по-прежнему возможен путём добавления начальной точки к имени модуля при использовании формы from ... import:

# Импорт имён из pkg.string
from .string import name1, name2
# Импорт pkg.string
from . import string

Это импортирует модуль string относительно текущего пакета, поэтому в pkg.main будут импортированы name1 и name2 из pkg.string. Дополнительные ведущие точки выполняют относительный импорт, начиная с родителя текущего пакета. Например, код в модуле A.B.C может подойти:

from . import D                 # Импортируются A.B.D
from .. import E                # Импортируются A.E
from ..F import G               # Импортируются A.F.G

Начальные точки нельзя использовать с формой import modname отчёта об импорте, только с формой from ... import.

См.также

PEP 328 — Импорт: многострочный и абсолютный/относительный
PEP, написанный Аазом; реализован Томасом Воутерсом.
https://pylib.readthedocs.io/
Библиотека py от Хольгер Крикет, содержащая пакет py.std.

PEP 338: Выполнение модулей как сценариев

Переключатель -m, добавленный в Python 2.4 для выполнения модуля, поскольку скрипт получил несколько дополнительных возможностей. Вместо реализации в коде C внутри интерпретатора Python переключатель теперь использует реализацию в новом модуле runpy.

Модуль runpy реализует более сложный механизм импорта, так что теперь можно запускать модули в пакете, таком как pychecker.checker. Модуль также поддерживает альтернативные механизмы импорта, такие как модуль zipimport. Это означает, что вы можете добавить путь ZIP-архива к sys.path, а затем использовать переключатель -m для выполнения кода из архива.

См.также

PEP 338 — Выполнение модулей как скриптов
PEP написан и реализован Ником Когланом.

PEP 341: Унифицированный try/except/finally

До Python 2.5 оператор try существовал в двух вариантах. Вы можете использовать блок finally, чтобы убедиться, что код всегда выполняется, или один или несколько блоков except, чтобы перехватывать определённые исключения. Вы не могли объединить оба блока except и блок finally, потому что создание правильного байт-кода для объединенной версии было сложным, и было неясно, какой должна быть семантика объединенного оператора.

Гвидо ван Россумом провел некоторое время, работая с Java, которая поддерживает эквивалент объединения блоков except и блока finally, и это прояснило, что должно означать утверждение. В Python 2.5 теперь вы можете писать:

try:
    block-1 ...
except Exception1:
    handler-1 ...
except Exception2:
    handler-2 ...
else:
    else-block
finally:
    final-block

Код в block-1 выполняется. Если код вызывает исключение, проверяются различные блоки except: если исключение относится к классу Exception1, выполняется handler-1; в противном случае, если это класс Exception2, выполняется handler-2 и так далее. Если исключение не вызывается, выполняется else-block.

Независимо от того, что произошло ранее, final-block выполняется после завершения блока кода и обработки любых возникших исключений. Даже если есть ошибка в обработчике исключений или else-block и вызывается новое исключение, код в final-block все ещё выполняется.

См.также

PEP 341 — объединение try-except и try-finally
PEP, написанный Георгом Брандлом; реализация Томаса Ли.

PEP 342: Новые функции генератора

В Python 2.5 добавлен простой способ передачи значений в генератор. Как было представлено в Python 2.3, генераторы производят только выходные данные; как только код генератора был вызван для создания итератора, не было возможности передать какую-либо новую информацию в функцию при возобновлении её выполнения. Иногда возможность передать некоторую информацию была бы полезна. Хакерские решения этой проблемы включают в себя то, что код генератора просматривает глобальную переменную, а затем изменяет значение глобальной переменной или передает некоторый изменяемый объект, который затем модифицируется вызывающими объектами.

Чтобы освежить вашу память об основных генераторах, вот простой пример:

def counter (maximum):
    i = 0
    while i < maximum:
        yield i
        i += 1

Когда вы вызываете counter(10), результатом является итератор, который возвращает значения от 0 до 9. При обнаружении оператора yield итератор возвращает предоставленное значение и приостанавливает выполнение функции, сохраняя локальные переменные. Выполнение возобновляется при следующем вызове метода итератора next() после оператора yield.

В Python 2.3 yield был оператором; он не вернул никакого значения. В версии 2.5 yield теперь является выражением, возвращающим значение, которое можно присвоить переменной или выполнить другую операцию:

val = (yield i)

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

(PEP 342 объясняет точные правила, а именно то, что выражение yield всегда должно быть заключено в скобки, за исключением случаев, когда оно встречается в выражении верхнего уровня в правой части присваивания. Это означает, что вы можете написать val = yield i, но должны использовать круглые скобки. когда есть операция, как в val = (yield i) + 12.)

Значения отправляются в генератор вызовом его метода send(value). Затем код генератора возобновляется, и выражение yield возвращает указанный value. Если вызывается обычный метод next(), yield возвращает None.

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

def counter (maximum):
    i = 0
    while i < maximum:
        val = (yield i)
        # Если указано значение, изменить счётчик
        if val is not None:
            i = val
        else:
            i += 1

А вот пример смены счетчика:

>>> it = counter(10)
>>> print it.next()
0
>>> print it.next()
1
>>> print it.send(8)
8
>>> print it.next()
9
>>> print it.next()
Traceback (most recent call last):
  File "t.py", line 15, in ?
    print it.next()
StopIteration

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

В дополнение к send() есть ещё два новых метода для генераторов:

  • throw(type, value=None, traceback=None) используется для создания исключения внутри генератора; исключение вызывается выражением yield, когда выполнение генератора приостанавливается.

  • close() вызывает новое исключение GeneratorExit внутри генератора, чтобы завершить итерацию. При получении этого исключения код генератора должен вызывать GeneratorExit или StopIteration. Перехват исключения GeneratorExit и возвращение значения недопустимы и вызовут ошибку RuntimeError; если функция вызывает какое-либо другое исключение, это исключение передаётся вызывающей стороне. close() также будет вызываться сборщиком мусора Python при сборке мусора генератором.

    Если вам нужно запустить код очистки, когда вызывается GeneratorExit, я предлагаю использовать пакет try: ... finally: вместо перехвата GeneratorExit.

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

Генераторы также становятся корутинами, более обобщенной формой подпрограмм. Вход в подпрограммы происходит в одной точке, а выход в другой (верхняя часть функции и оператор return), но вход в сопрограммы, выход из них и возобновление работы могут выполняться во многих разных точках (операторы yield). Нам нужно выяснить шаблоны для эффективного использования корутин в Python.

Добавление метода close() имеет один побочный эффект, который не очевиден. close() вызывается, когда генератор подвергается сборке мусора, поэтому это означает, что код генератора получает последний шанс запуститься перед тем, как генератор будет уничтожен. Данный последний шанс означает, что операторы try...finally в генераторах теперь могут гарантированно работать; пункт finally теперь всегда будет выполняться. Таким образом, синтаксическое ограничение, запрещающее смешивать операторы yield с набором try...finally, было снято. Это кажется незначительным языковым пустяком, но использование генераторов и try...finally на самом деле необходимо для реализации оператора with, описанного PEP 343. Я рассмотрю это новое утверждение в следующем разделе.

Другой, ещё более эзотерический эффект этого изменения: ранее атрибут генератора gi_frame всегда был объектом фрейма. Теперь возможно, что gi_frame станет None после того, как генератор разрядится.

См.также

PEP 342 — Корутины через расширенные генераторы

PEP, написанный Гвидо ван Россумом и Филипп Дж. Эби; реализованный Филиппом Дж. Эби. Включает примеры более необычного использования генераторов в качестве корутин.

Более ранние версии данных функций были предложены в PEP 288 Raymond Hettinger и PEP 325 Samuele Pedroni.

https://en.wikipedia.org/wiki/Корутина
Запись в Википедии о корутинах.
http://www.sidhe.org/~dan/blog/archives/000178.html
Объяснение корутин с точки зрения Perl, написанное Дэном Сугалски.

PEP 343: Оператор with

Оператор «with» разъясняет код, который ранее использовал блоки try...finally, чтобы обеспечить выполнение кода очистки. В этом разделе я расскажу об этом утверждении, поскольку оно будет часто использоваться. В следующем разделе я рассмотрю детали реализации и покажу, как писать объекты для использования с этим оператором.

Оператор «with» — это новая структура потока управления, основная структура которой такова:

with expression [as variable]:
    with-block

Выражение вычисляется, и в результате должен получиться объект, поддерживающий протокол управления контекстом. (Т. е. у него есть методы __enter__() и __exit__().)

__enter__() объекта вызывается перед выполнением with-block и, следовательно, может запускать код установки. Он также может возвращать значение, связанное с именем variable, если оно задано. (Обратите внимание, что variableне присвоенный результат expression.)

После завершения выполнения with-block вызывается метод объекта __exit__(), даже если блок вызвал исключение, и, следовательно, может выполнять код очистки.

Чтобы включить оператор в Python 2.5, вам нужно добавить следующую директиву в ваш модуль:

from __future__ import with_statement

Оператор всегда будет включён в Python 2.6.

Некоторые стандартные объекты Python теперь поддерживают протокол управления контекстом и могут использоваться с оператором «with». Файловые объекты являются одним из примеров:

with open('/etc/passwd', 'r') as f:
    for line in f:
        print line
        ... больше кода обработки ...

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

Примечание

В этом случае f — это тот же объект, созданный open(), поскольку file.__enter__() возвращает self.

Блокировки и условные переменные модуля threading также поддерживают оператор with:

lock = threading.Lock()
with lock:
    # Критическая часть кода
    ...

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

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

from decimal import Decimal, Context, localcontext

# Отображает с точностью по умолчанию 28 цифр
v = Decimal('578')
print v.sqrt()

with localcontext(Context(prec=16)):
    # Весь код в этом блоке использует точность 16 цифр.
    # Исходный контекст восстанавливается при выходе из блока.
    print v.sqrt()

Написание менеджеров контекста

Под капотом оператор «with» довольно сложен. Большинство людей будут использовать «with» только в компании с существующими объектами, и им не нужно знать данные подробности, поэтому вы можете пропустить оставшуюся часть этого раздела, если хотите. Авторы новых объектов должны понимать детали базовой реализации и должны продолжать чтение.

Высокоуровневое объяснение протокола управления контекстом:

  • Выражение вычисляется и должно привести к объекту, который называется «менеджер контекста». Менеджер контекста должен иметь методы __enter__() и __exit__().
  • Вызывается метод __enter__() менеджера контекста. Возвращаемое значение присваивается VAR. Если предложение 'as VAR' отсутствует, значение просто отбрасывается.
  • Код в BLOCK выполняется.
  • Если BLOCK вызывает исключение, вызывается __exit__(type, value, traceback) с подробностями исключения, те же значения возвращаются sys.exc_info(). Возвращаемое значение метода определяет, будет ли повторно вызываться исключение: любое ложное значение повторно вызывает исключение, а True приведёт к его подавлению. Вы редко захотите подавить исключение, потому что, если сделать это, автор содержащего оператор «with» кода, никогда не поймет, что что-то пошло не так.
  • Если BLOCK не вызывает исключения, метод __exit__() по-прежнему вызывается, но type, value и traceback — все None.

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

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

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

db_connection = DatabaseConnection()
with db_connection as cursor:
    cursor.execute('insert into ...')
    cursor.execute('delete from ...')
    # ... больше действий ...

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

class DatabaseConnection:
    # Интерфейс базы данных
    def cursor (self):
        "Возвращает объект курсора и запускает новую транзакцию"
    def commit (self):
        "Фиксирует текущую транзакцию"
    def rollback (self):
        "Откатывает текущую транзакцию"

Метод __enter__() довольно прост, нужно только начать новую транзакцию. Для этого приложения результирующий объект курсора будет полезным результатом, поэтому метод вернёт его. Затем пользователь может добавить as cursor к своему оператору «with», чтобы привязать курсор к имени переменной.

class DatabaseConnection:
    ...
    def __enter__ (self):
        # Код для начала новой транзакции
        cursor = self.cursor()
        return cursor

Метод __exit__() является самым сложным, поскольку именно с ним приходится выполнять большую часть работы. Метод должен проверить, произошло ли исключение. Если исключения не было, транзакция фиксируется. Транзакция откатывается, если возникло исключение.

В приведённом ниже коде выполнение просто упадет с конца функции, возвращая значение по умолчанию None. None имеет значение ложь, поэтому исключение будет сгенерировано автоматически. Если вы хотите, вы можете быть более явным и добавить оператор return в отмеченном месте.

class DatabaseConnection:
    ...
    def __exit__ (self, type, value, tb):
        if tb is None:
            # Не исключение, так что коммит
            self.commit()
        else:
            # Произошло исключение, поэтому откат.
            self.rollback()
            # return False

Модуль contextlib

Новый модуль contextlib предоставляет некоторые функции и декоратор, полезные для написания объектов для использования с оператором with.

Декоратор называется contextmanager() и позволяет вам написать одну функцию-генератор вместо определения нового класса. Генератор должен выдать ровно одно значение. Код до yield будет выполняться как метод __enter__(), а полученное значение будет возвращаемым значением метода, которое будет привязано к переменной в предложении as оператора «with», если таковое имеется. Код после yield будет выполняться в методе __exit__(). Любое исключение, вызванное в блоке, будет вызвано оператором yield.

Наш пример базы данных из предыдущего раздела может быть написан с использованием этого декоратора как:

from contextlib import contextmanager

@contextmanager
def db_transaction (connection):
    cursor = connection.cursor()
    try:
        yield cursor
    except:
        connection.rollback()
        raise
    else:
        connection.commit()

db = DatabaseConnection()
with db_transaction(db) as cursor:
    ...

Модуль contextlib также имеет функцию nested(mgr1, mgr2, ...), которая объединяет несколько менеджеров контекста, поэтому вам не нужно писать вложенные операторы «with». В этом примере один оператор «with» запускает транзакцию базы данных и получает блокировку потока:

lock = threading.Lock()
with nested (db_transaction(db), lock) as (cursor, locked):
    ...

Наконец, функция closing(object) возвращает object, чтобы её можно было связать с переменной, и вызывает object.close в конце блока.

import urllib, sys
from contextlib import closing

with closing(urllib.urlopen('http://www.yahoo.com')) as f:
    for line in f:
        sys.stdout.write(line)

См.также

PEP 343 — Оператор with
PEP, написанный Гвидо ван Россумом и Nick Coghlan; реализованный Майком Блэндом Гвидо ван Россумом и Нил Норвиц. PEP показывает код, сгенерированный для a Оператор «with», который может быть полезен при изучении того, как оператор работает.

Документация для модуля contextlib.

PEP 352: исключения как классы нового стиля

Классы исключений теперь могут быть классами нового стиля, а не только классическими классами, а встроенный класс Exception и все стандартные встроенные исключения (NameError, ValueError и т. д.) теперь являются классами нового стиля.

Немного изменена иерархия наследования исключений. В версии 2.5 отношения наследования такие:

|- KeyboardInterrupt
|- SystemExit
|- Exception
BaseException       # новое в Python 2.5
   |- (все остальные текущие встроенные исключения)

Реорганизация была сделана потому, что люди часто хотят перехватывать все исключения, указывающие на ошибки программы. Однако KeyboardInterrupt и SystemExit не являются ошибками и обычно представляют явное действие, такое как нажатие пользователем Control-C или код, вызывающий sys.exit(). Пустой except: будет перехватывать все исключения, поэтому вам обычно нужно перечислить KeyboardInterrupt и SystemExit, чтобы повторно вызывать их. Обычная схема такая:

try:
    ...
except (KeyboardInterrupt, SystemExit):
    raise
except:
    # Журналирование ошибки ...
    # Продолжить выполнение программы...

В Python 2.5 теперь вы можете написать except Exception для достижения того же результата, перехватив все исключения, которые обычно указывают на ошибки, но оставив только KeyboardInterrupt и SystemExit. Как и в предыдущих версиях, голый except: по-прежнему перехватывает все исключения.

Цель Python 3.0 — потребовать, чтобы любой класс, вызванный как исключение, производился от BaseException или какого-либо потомка BaseException, и будущие релизы серии Python 2.x могут начать применять это ограничение. Поэтому я предлагаю вам начать делать все ваши классы исключений производными от Exception прямо сейчас. Было предложено удалить пустую форму except: в Python 3.0, но Гвидо ван Россумом ещё не решил, делать это или нет.

Вызов строк как исключений, как в операторе raise "Error occurred", устарел в Python 2.5 и вызовет предупреждение. Цель состоит в том, чтобы иметь возможность удалить функцию строковых исключений в нескольких выпусках.

См.также

PEP 352 — обязательный суперкласс для исключений
PEP, написанный Бреттом Кэнноном и Гвидо ван Россумом; реализован Бреттом Кэнноном.

PEP 353: Использование ssize_t в качестве типа индекса

Масштабное изменение Python C API с использованием нового определения типа Py_ssize_t вместо int позволит интерпретатору обрабатывать больше данных на 64-битных платформах. Это изменение не влияет на возможности Python на 32-разрядных платформах.

Различные части интерпретатора Python использовали тип C int для хранения размеров или количества; например, количество элементов в списке или кортеже было сохранено в int. Компиляторы C для большинства 64-битных платформ по-прежнему определяют int как 32-битный тип, а это означает, что списки могут содержать только до 2**31 - 1 = 2147483647 элементов. (На самом деле существует несколько разных моделей программирования, которые могут использовать 64-битные компиляторы C — см. http://www.unix.org/version2/whatsnew/lp64_wp.html для обсуждения — но наиболее распространенная модель оставляет int. как 32 бит.)

Ограничение в 2 147 483 647 элементов на 32-битной платформе не имеет большого значения, потому что вам не хватит памяти, прежде чем вы достигнете предела длины. Для каждого элемента списка требуется место для указателя (4 байта) плюс место для PyObject, представляющего элемент. 2147483647*4 — это уже больше байтов, чем может содержать 32-битное адресное пространство.

Однако можно адресовать такой объем памяти на 64-битной платформе. Указатели для списка такого размера потребуют всего 16 ГиБ пространства, поэтому вполне разумно, что программисты Python могут создавать такие большие списки. Поэтому интерпретатор Python пришлось изменить, чтобы использовать какой-либо тип, отличный от int, и это будет 64-битный тип на 64-битных платформах. Это изменение вызовет несовместимость на 64-битных машинах, поэтому было решено сделать переход сейчас, пока число 64-битных пользователей все ещё относительно невелико. (Через 5 или 10 лет мы можем использовать все на 64-битных машинах, и тогда переход будет более болезненным.)

Это изменение сильнее всего затронет авторов модулей расширения C. Строки Python и типы контейнеров, такие как списки и кортежи, теперь используют Py_ssize_t для хранения своего размера. Такие функции, как PyList_Size(), теперь возвращают Py_ssize_t. Поэтому код в модулях расширения может потребовать изменения некоторых переменных на Py_ssize_t.

Функции PyArg_ParseTuple() и Py_BuildValue() имеют новый код преобразования n для Py_ssize_t. s# и t# PyArg_ParseTuple() по-прежнему выводят int по умолчанию, но вы можете определить макрос PY_SSIZE_T_CLEAN перед включением Python.h, чтобы они возвращали Py_ssize_t.

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

См.также

PEP 353 — использование ssize_t в качестве типа индекса
PEP написан и реализован Мартином фон Лёвисом.

PEP 357: метод __index__

У разработчиков NumPy возникла проблема, которую можно было решить, только добавив новый специальный метод __index__(). При использовании нотации среза, как в [start:stop:step], значения индексов start, stop и step должны быть целыми или длинными целыми числами. NumPy определяет множество специализированных целочисленных типов, соответствующих целым числам без знака и со знаком размером 8, 16, 32 и 64 бита, но не было способа указать, что данные типы можно использовать в качестве индексов срезов.

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

Вместо этого был добавлен новый специальный метод __index__(). Он не принимает аргументов и возвращает целое число, задающее используемый индекс среза. Например:

class C:
    def __index__ (self):
        return self.value

Возвращаемое значение должно быть целым числом Python или длинным целым числом. Интерпретатор проверит правильность возвращаемого типа и выдаст TypeError, если это требование не будет выполнено.

Соответствующий слот nb_index был добавлен в структуру PyNumberMethods уровня C, чтобы позволить расширениям C реализовать данный протокол. PyNumber_Index(obj) можно использовать в коде расширения для вызова функции __index__() и получения её результата.

См.также

PEP 357 — Разрешение использования любого объекта для нарезки
PEP написан и реализован Трэвисом Олифантом.

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

Вот все изменения, которые Python 2.5 вносит в основной язык Python.

  • Тип dict имеет новый хук, позволяющий подклассам предоставлять значение по умолчанию, когда ключ не содержится в словаре. Если ключ не найден, будет вызван метод словаря __missing__(key). Данный хук используется для реализации нового класса defaultdict в модуле collections. В следующем примере определяется словарь, который возвращает ноль для любого отсутствующего ключа:

    class zerodict (dict):
        def __missing__ (self, key):
            return 0
    
    d = zerodict({1:1, 2:2})
    print d[1], d[2]   # Prints 1, 2
    print d[3], d[4]   # Prints 0, 0
    
  • И 8-битные строки, и строки Юникод имеют новые методы partition(sep) и rpartition(sep), которые упрощают общий вариант использования.

    Метод find(S) часто используется для получения индекса, который затем используется для нарезки строки и получения фрагментов до и после разделителя. partition(sep) объединяет данный шаблон в один вызов метода, который возвращает 3-кортеж, содержащий подстроку перед разделителем, сам разделитель и подстроку после разделителя. Если разделитель не найден, первым элементом кортежа является вся строка, а два других элемента пусты. rpartition(sep) также возвращает тройку, но начинает поиск с конца строки; r означает «реверс».

    Несколько примеров:

    >>> ('http://www.python.org').partition('://')
    ('http', '://', 'www.python.org')
    >>> ('file:/usr/share/doc/index.html').partition('://')
    ('file:/usr/share/doc/index.html', '', '')
    >>> (u'Subject: a quick question').partition(':')
    (u'Subject', u':', u' a quick question')
    >>> 'www.python.org'.rpartition('.')
    ('www.python', '.', 'org')
    >>> 'www.python.org'.rpartition(':')
    ('', '', 'www.python.org')
    

    (Реализовано Фредриком Лундом по предложению Рэймонда Хеттингера.)

  • Методы строковых типов startswith() и endswith() теперь принимают кортежи строк для проверки.

    def is_image_file (filename):
        return filename.endswith(('.gif', '.jpg', '.tiff'))
    

    (Реализовано Георгом Брандлом по предложению Тома Линна.)

  • Встроенные функции min() и max() получили ключевой параметр key, аналогичный аргументу key для sort(). Данный параметр предоставляет функцию, которая принимает один аргумент и вызывается для каждого значения в списке; min()/max() вернёт элемент с наименьшим/наибольшим возвращаемым значением из этой функции. Например, чтобы найти самую длинную строку в списке, вы можете сделать это:

    L = ['medium', 'longest', 'short']
    # Печатает 'longest'
    print max(L, key=len)
    # Печатает 'short', потому что лексикографически 'short' имеет наибольшее значение
    print max(L)
    

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

  • Две новые встроенные функции any() и all(), вычисляют, содержит ли итератор какие-либо значения истина или ложь. any() возвращает True, если любое значение, возвращаемое итератором, истинно; в противном случае он вернёт False. all() возвращает True, только если все значения, возвращаемые итератором, вычисляются как истинные. (Предложено Гвидо ван Россумом и реализовано Рэймондом Хеттингером.)

  • Результатом метода класса __hash__() теперь может быть либо длинное целое число, либо обычное целое число. Если возвращается длинное целое число, берется хэш этого значения. В более ранних версиях хеш-значение должно было быть обычным целым числом, но в версии 2.5 встроенный id() был изменён, чтобы всегда возвращать неотрицательные числа, и пользователи часто используют id(self) в методах __hash__() (хотя это не рекомендуется).

  • ASCII теперь является кодировкой по умолчанию для модулей. Теперь это синтаксическая ошибка, если модуль содержит строковые литералы с 8-битными символами, но не имеет объявления кодировки. В Python 2.4 это вызвало предупреждение, а не синтаксическую ошибку. См. PEP 263, чтобы узнать, как объявить кодировку модуля; например, вы можете добавить такую строку вверху исходного файла:

    # -*- coding: latin1 -*-
    
  • Новое предупреждение UnicodeWarning выдается при попытке сравнить строку Юникод и 8-битную строку, которую нельзя преобразовать в Юникод с использованием кодировки ASCII по умолчанию. Результат сравнения ложный:

    >>> chr(128) == unichr(128)   # Не удается преобразовать chr(128) в Юникод
    __main__:1: UnicodeWarning: Unicode equal comparison failed
      to convert both arguments to Unicode - interpreting them
      as being unequal
    False
    >>> chr(127) == unichr(127)   # chr(127) можно преобразовать
    True
    

    Раньше это вызывало исключение UnicodeDecodeError, но в версии 2.5 это могло привести к непонятным проблемам при доступе к словарю. Если бы вы искали unichr(128), а chr(128) использовался в качестве ключа, вы бы получили исключение UnicodeDecodeError. Другие изменения в версии 2.5 привели к тому, что это исключение было вызвано, а не подавлено кодом в dictobject.c, который реализует словари.

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

    (Реализовано Марком-Андре Лембургом.)

  • Одна ошибка, которую иногда допускают программисты Python, заключается в том, что они забывают включить модуль __init__.py в каталог пакета. Отладка этой ошибки может привести к путанице и обычно требует запуска Python с параметром -v для регистрации всех найденных путей. В Python 2.5 новое предупреждение ImportWarning срабатывает, когда импорт должен был выбрать каталог как пакет, но __init__.py не был найден. Это предупреждение по умолчанию игнорируется; указать параметр -Wd при запуске исполняемого файла Python для отображения предупреждающего сообщения. (Реализовано Томасом Воутерсом.)

  • Список базовых классов в определении класса теперь может быть пустым. Например, теперь это законно:

    class C():
        pass
    

    (Реализовано Бреттом Кэнноном.)

Изменения интерактивного интерпретатора

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

>>> quit
'Use Ctrl-D (i.e. EOF) to exit.'

В Python 2.5 quit и exit теперь являются объектами, которые по-прежнему создают строковые представления самих себя, но также могут вызываться. Новички, которые пробуют quit() или exit(), теперь будут выходить из интерпретатора, как они и ожидали. (Реализовано Георгом Брандлом.)

Исполняемый файл Python теперь принимает стандартные длинные параметры --help и --version; в Windows он также принимает параметр /? для отображения справочного сообщения. (Реализовано Георгом Брандлом.)

Оптимизации

Несколько оптимизаций были разработаны во время спринта NeedForSpeed, мероприятия, проходившего в Рейкьявике, Исландия, с 21 по 28 мая 2006 года. Спринт был сосредоточен на повышении скорости реализации CPython и финансировался EWT LLC при местной поддержке CCP Games. Оптимизации, добавленные в этом спринте, отмечены в следующем списке.

  • Когда они были представлены в Python 2.4, встроенные типы set и frozenset были построены поверх словарного типа Python. В версии 2.5 внутренняя структура данных была настроена для реализации наборов, в результате чего наборы будут использовать на треть меньше памяти и работать несколько быстрее. (Реализован Раймондом Хеттингером.)
  • Повышена скорость некоторых операций Юникод, например поиск подстрок, разбиение строк, а также кодирование и декодирование карты символов. (Улучшения поиска подстрок и разделения были добавлены Фредриком Лундом и Эндрю Далке во время спринта NeedForSpeed. Карты символов были улучшены Вальтером Дёрвальдом и Мартином фон Лёвисом.)
  • Функция long(str, base) теперь работает быстрее для длинных строк цифр, поскольку вычисляется меньше промежуточных результатов. Пик приходится на строки из 800-1000 цифр, где функция работает в 6 раз быстрее. (Предоставлено Аланом Макинтайром и зафиксировано в спринте NeedForSpeed.)
  • Теперь незаконно смешивать итерацию по файлу с for line in file и вызов методов файлового объекта read()/readline()/readlines(). Итерация использует внутренний буфер, а методы read*() не используют данный буфер. Вместо этого они будут возвращать данные после буфера, в результате чего данные будут отображаться не по порядку. Смешанная итерация и данные методы теперь вызовут ValueError из метода read*(). (Реализовано Томасом Воутерсом.)
  • Модуль struct теперь компилирует строки формата структуры во внутреннее представление и кэширует это представление, что дает ускорение на 20%. (Представлено Бобом Ипполито на спринте NeedForSpeed.)
  • Модуль re получил ускорение на 1 или 2% за счет переключения на функции распределителя Python вместо системных malloc() и free(). (Представлено Джеком Дидерихом на спринте NeedForSpeed.)
  • Оптимизатор глазка генератора кода теперь выполняет простое свертывание констант в выражениях. Если вы напишете что-то вроде a = 2+3, генератор кода выполнит арифметические действия и создаст код, соответствующий a = 5. (Предложено и реализовано Раймондом Хеттингером.)
  • Вызовы функций теперь выполняются быстрее, поскольку объекты кода теперь сохраняют самый последний законченный фрейм («фрейм зомби») во внутреннем поле объекта кода, повторно используя его при следующем вызове объекта кода. (Исходный патч Майкла Хадсона, измененный Армином Риго и Ричардом Джонсом; добавлен на спринте NeedForSpeed.) Объекты фреймов также немного меньше, что может улучшить локальность кеша и немного уменьшить использование памяти. (Предоставлено Нилом Норвицем.)
  • Встроенные исключения Python теперь представляют собой классы нового стиля, изменение, которое значительно ускоряет создание экземпляров. Таким образом, обработка исключений в Python 2.5 примерно на 30% быстрее, чем в версии 2.4. (Предоставлено Ричардом Джонсом, Георгом Брандлом и Шоном Рейфшнайдером на спринте NeedForSpeed)
  • Импорт теперь кэширует проверенные пути, записывая, существуют они или нет, чтобы интерпретатор делал меньше вызовов open() и stat() при запуске. (Предоставлено Мартином фон Лёвисом и Георгом Брандлом)

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

Стандартная библиотека получила множество улучшений и исправлений ошибок в Python 2.5. Вот неполный список наиболее заметных изменений, отсортированных в алфавитном порядке по имени модуля. Обратитесь к файлу Misc/NEWS в исходном дереве для получения более полного списка изменений или просмотрите все подробности в журналах SVN.

  • Модуль audioop теперь поддерживает кодировку a-LAW, а код для кодировки u-LAW был улучшен. (Предоставлено Ларсом Иммишем.)

  • Модуль codecs получил поддержку инкрементных кодеков. Функция codec.lookup() теперь возвращает экземпляр CodecInfo вместо кортежа. Экземпляры CodecInfo ведут себя как 4-кортежи для сохранения обратной совместимости, но также имеют атрибуты encode, decode, incrementalencoder, incrementaldecoder, streamwriter и streamreader. Инкрементные кодеки могут получать входные данные и создавать выходные данные несколькими порциями; вывод такой же, как если бы весь ввод был передан неинкрементному кодеку. Подробности смотрите в документации модуля codecs. (Разработано и реализовано Вальтером Дёрвальдом.)

  • Модуль collections получил новый тип defaultdict, который является подклассом стандартного типа dict. Новый тип в основном ведёт себя как словарь, но создаёт значение по умолчанию, когда ключ отсутствует, автоматически добавляя его в словарь для запрошенного значения ключа.

    Первый аргумент конструктора defaultdict — это фабричная функция, которая вызывается каждый раз, когда запрашивается ключ, но он не найден. Эта фабричная функция не получает аргументов, поэтому вы можете использовать встроенные конструкторы типов, такие как list() или int(). Например, вы можете сделать указатель слов на основе их начальной буквы следующим образом:

    words = """Nel mezzo del cammin di nostra vita
    mi ritrovai per una selva oscura
    che la diritta via era smarrita""".lower().split()
    
    index = defaultdict(list)
    
    for w in words:
        init_letter = w[0]
        index[init_letter].append(w)
    

    Печать index приводит к следующему результату:

    defaultdict(<type 'list'>, {'c': ['cammin', 'che'], 'e': ['era'],
            'd': ['del', 'di', 'diritta'], 'm': ['mezzo', 'mi'],
            'l': ['la'], 'o': ['oscura'], 'n': ['nel', 'nostra'],
            'p': ['per'], 's': ['selva', 'smarrita'],
            'r': ['ritrovai'], 'u': ['una'], 'v': ['vita', 'via']}
    

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

  • Тип двусторонней очереди deque, предоставляемый модулем collections, теперь имеет метод remove(value), удаляющий первое вхождение value в очереди и поднимающий ValueError, если значение не найдено. (Предоставлено Рэймондом Хеттингером.)

  • Новый модуль: модуль contextlib содержит вспомогательные функции для использования с новым оператором «with». Подробнее об этом модуле см. в разделе Модуль contextlib.

  • Новый модуль: модуль cProfile — это реализация существующего модуля profile на языке C, которая имеет гораздо меньшие накладные расходы. Интерфейс модуля такой же, как у profile: вы запускаете cProfile.run('main()') для профилирования функции, можете сохранять данные профиля в файл и т. д. Пока неизвестно, работает ли профилировщик Hotshot, который также написан на C, но не соответствует интерфейс, будет по- прежнему поддерживаться в будущих версиях Python. (Предоставлено Армином Риго.)

    Кроме того, модуль pstats для анализа данных, измеренных профилировщиком, теперь поддерживает направление вывода на любой файловый объект путём предоставления аргумента stream конструктору Stats. (Предоставлено Скипом Монтанаро.)

  • Модуль csv, анализирующий файлы в формате значений, разделенных запятыми, получил несколько улучшений и ряд исправлений. Теперь вы можете установить максимальный размер поля в байтах, вызвав функцию csv.field_size_limit(new_limit); отсутствие аргумента new_limit вернёт текущий установленный лимит. Класс reader теперь имеет атрибут line_num, который подсчитывает количество физических строк, считанных из источника; записи могут охватывать несколько физических строк, поэтому line_num не совпадает с количеством прочитанных записей.

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

    (Предоставили Скип Монтанаро и Эндрю Макнамара.)

  • Класс datetime в модуле datetime теперь имеет метод strptime(string, format) для синтаксического анализа строк даты, предоставленный Джошем Споерри. Он использует те же символы формата, что и time.strptime() и time.strftime():

    from datetime import datetime
    
    ts = datetime.strptime('10:13:15 2006-03-07',
                           '%H:%M:%S %Y-%m-%d')
    
  • Метод SequenceMatcher.get_matching_blocks() в модуле difflib теперь гарантирует возвращение минимального списка блоков, определяющих совпадающие подпоследовательности. Раньше алгоритм иногда разбивал блок совпадающих элементов на две записи списка. (Улучшение Тимом Питерсом.)

  • Модуль doctest получил параметр SKIP, который вообще запрещает выполнение примера. Это предназначено для фрагментов кода, которые являются примерами использования, предназначенными для читателя, а не тестовыми примерами.

    Параметр encoding был добавлен в функцию testfile() и класс DocFileSuite для указания кодировки файла. Это упрощает использование символов, отличных от ASCII, в тестах, содержащихся в строке документации. (Предоставлено Бьорном Тиллениусом.)

  • Пакет email обновлен до версии 4.0. (Предоставлено Барри Варшавой.)

  • Модуль fileinput стал более гибким. Теперь поддерживаются имена файлов в формате Юникод, а параметр mode, который по умолчанию равен "r", был добавлен в функцию input(), чтобы разрешить открытие файлов в двоичном режиме или в режиме универсального символа новой строки. Ещё один новый параметр, openhook, позволяет использовать функцию, отличную от open(), для открытия входных файлов. Как только вы перебираете множество файлов, новый fileno() объекта FileInput возвращает файловый дескриптор для текущего открытого файла. (Предоставлено Георгом Брандлом.)

  • В модуле gc новая функция get_count() возвращает тройку, содержащую текущие счетчики коллекций для трех поколений GC. Это учетная информация для сборщика мусора; когда данные значения достигают заданного порога, выполняется очистка сборки мусора. Существующая функция gc.collect() теперь принимает необязательный аргумент generation, равный 0, 1 или 2, чтобы указать, какое поколение собирать. (Предоставлено Барри Варшавой.)

  • Функции nsmallest() и nlargest() в модуле heapq теперь поддерживают ключевой параметр key, аналогичный параметру, предоставляемому функциями min()/max() и методами sort(). Например:

    >>> import heapq
    >>> L = ["short", 'medium', 'longest', 'longer still']
    >>> heapq.nsmallest(2, L)  # Возвращает два младших элемента лексикографически
    ['longer still', 'longest']
    >>> heapq.nsmallest(2, L, key=len)   # Возвращает два кратчайших элемента
    ['short', 'medium']
    

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

  • Функция itertools.islice() теперь принимает None в качестве аргументов начала и шага. Это делает его более совместимым с атрибутами объектов-срезов, так что теперь вы можете написать следующее:

    s = slice(5)     # Создать объект среза
    itertools.islice(iterable, s.start, s.stop, s.step)
    

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

  • Функция format() в модуле locale была изменена, и были добавлены две новые функции, format_string() и currency().

    Параметр val функции format() ранее мог быть строкой, если отображалось не более одного спецификатора %char; теперь параметр должен быть ровно одним спецификатором %char без окружающего текста. Также был добавлен необязательный параметр monetary, который, если True, будет использовать правила локали для форматирования валюты при размещении разделителя между группами из трех цифр.

    Для форматирования строк с несколькими спецификаторами %char используйте новую функцию format_string(), которая работает аналогично format(), но также поддерживает смешивание спецификаторов %char с произвольным текстом.

    Также была добавлена новая функция currency(), которая форматирует число в соответствии с настройками текущей локали.

    (Предоставлено Георгом Брандлом.)

  • Модуль mailbox был значительно переписан, чтобы добавить возможность изменять почтовые ящики в дополнение к их чтению. Новый множество классов, включающий mbox, MH и Maildir, используется для чтения почтовых ящиков и имеет метод add(message) для добавления сообщений, remove(key) для удаления сообщений и lock()/unlock() для блокировки/разблокировки почтового ящика. В следующем примере почтовый ящик формата maildir преобразуется в формат mbox:

    import mailbox
    
    # 'factory=None' использует email.Message.Message как представляющий класс
    # отдельные сообщения.
    src = mailbox.Maildir('maildir', factory=None)
    dest = mailbox.mbox('/tmp/mbox')
    
    for msg in src:
        dest.add(msg)
    

    (Предоставил Грегори К. Джонсон. Финансирование было предоставлено компанией Google Summer of Code 2005 г.)

  • Новый модуль: модуль msilib позволяет создавать файлы Microsoft Installer .msi и CAB-файлы. Также включена некоторая поддержка чтения базы данных .msi. (Предоставлено Мартином фон Лёвисом.)

  • Модуль nis теперь поддерживает доступ к доменам, отличным от системного домена по умолчанию, путём предоставления аргумента domain функциям nis.match() и nis.maps(). (Предоставлено Беном Беллом.)

  • Функции itemgetter() и attrgetter() модуля operator теперь поддерживают несколько полей. Такой вызов, как operator.attrgetter('a', 'b'), вернёт функцию, которая извлекает атрибуты a и b. Сочетание этой новой функции с параметром key метода sort() позволяет легко сортировать списки с использованием нескольких полей. (Предоставлено Рэймондом Хеттингером.)

  • Модуль optparse обновлен до версии 1.5.1 библиотеки Optik. Класс OptionParser получил атрибут epilog, строку, которая будет напечатана после справочного сообщения, и метод destroy() для прерывания циклов ссылок, созданных объектом. (Предоставлено Грегом Уордом.)

  • Модуль os претерпел несколько изменений. Переменная stat_float_times теперь по умолчанию имеет значение истина, а это означает, что os.stat() теперь будет возвращать значения времени в виде чисел с плавающей запятой. (Это не обязательно означает, что os.stat() будет возвращать время с точностью до долей секунды; не все системы поддерживают такую точность.)

    Добавлены константы с именами os.SEEK_SET, os.SEEK_CUR и os.SEEK_END; это параметры функции os.lseek(). Две новые константы для блокировки — os.O_SHLOCK и os.O_EXLOCK.

    Были добавлены две новые функции, wait3() и wait4(). Они похожи на функцию waitpid(), которая ожидает завершения дочернего процесса и возвращает кортеж с идентификатором процесса и его статусом выхода, но wait3() и wait4() возвращают дополнительную информацию. wait3() не принимает идентификатор процесса в качестве входных данных, поэтому он ожидает завершения любого дочернего процесса и возвращает тройку из process-id, exit-status, resource-usage, возвращаемую функцией resource.getrusage(). wait4(pid) принимает идентификатор процесса. (Предоставлено Чадом Дж. Шредером.)

    Во FreeBSD функция os.stat() теперь возвращает время с разрешением в наносекунды, а возвращаемый объект теперь имеет st_gen и st_birthtime. Также доступен атрибут st_flags, если платформа его поддерживает. (Предоставили Антти Луко и Диего Петтено.)

  • Отладчик Python, предоставляемый модулем pdb, теперь может хранить списки команд для выполнения при достижении точки останова и остановке выполнения. После создания точки останова #1 введите commands 1 и серию команд для выполнения, закончив список end. Список команд может включать команды, которые возобновляют выполнение, например continue или next. (Предоставлено Грегуаром Думсом)

  • Модули pickle и cPickle больше не принимают возвращаемое значение None из метода __reduce__(); вместо этого метод должен возвращать кортеж аргументов. Возможность возвращать None устарела в Python 2.4, так что это завершает удаление функции.

  • Модуль pkgutil, содержащий различные служебные функции для поиска пакетов, был улучшен для поддержки перехватчиков импорта PEP 302 и теперь также работает с пакетами, хранящимися в ZIP-архивах. (Предоставлено Филиппом Дж. Эби.)

  • Множество тестов pybench от Марка-Андре Лембурга теперь включён в каталог Tools/pybench. Пакет pybench является усовершенствованием широко используемой программы pystone.py, поскольку pybench обеспечивает более подробное измерение скорости интерпретатора. Он измеряет время определенных операций, например вызовы функций, нарезка кортежей, поиск методов и числовые операции, вместо того, чтобы выполнять множество различных операций и сводить результат к одному числу, как это делает pystone.py.

  • Модуль pyexpat теперь использует версию 2.0 парсера Expat. (Предоставлено Трентом Миком.)

  • Класс Queue, предоставляемый модулем Queue, получил два новых метода. join() блокируется до тех пор, пока не будут получены все элементы в очереди и не будет завершена вся работа по обработке элементов. Рабочие потоки вызывают другой новый метод, task_done(), чтобы сообщить, что обработка элемента завершена. (Предоставлено Рэймондом Хеттингером.)

  • Старые модули regex и regsub, которые устарели ещё со времен Python 2.0, наконец-то удалены. Другие удаленные модули: statcache, tzparse, whrandom.

  • Также удалено: удален каталог lib-old, в который входят такие древние модули, как dircmp и ni. lib-old не был в sys.path по умолчанию, поэтому, если ваши программы явно не добавили каталог в sys.path, это удаление не должно повлиять на ваш код.

  • Модуль rlcompleter больше не зависит от импорта модуля readline и поэтому теперь работает на платформах, отличных от Unix. (Патч от Роберта Киндла.)

  • Классы SimpleXMLRPCServer и DocXMLRPCServer теперь имеют атрибут rpc_paths, ограничивающий операции XML-RPC ограниченным набором URL-адресов; по умолчанию разрешены только '/' и '/RPC2'. Установка rpc_paths в None или пустой кортеж отключает эту проверку пути.

  • Модуль socket теперь поддерживает сокеты AF_NETLINK в Linux благодаря патчу от Philippe Biondi. Сокеты Netlink — это специфичный для Linux механизм связи между процессом пользовательского пространства и кодом ядра; вводная статья о них находится по адресу https://www.linuxjournal.com/article/7356. В коде Python адреса сетевых ссылок представлены в виде кортежа из двух целых чисел, (pid, group_mask).

    Два новых метода для объектов сокетов, recv_into(buffer) и recvfrom_into(buffer), сохраняют полученные данные в объекте, который поддерживает протокол буфера, вместо того, чтобы возвращать данные в виде строки. Это означает, что вы можете поместить данные непосредственно в массив или в отображаемый в память файл.

    Объекты Socket также получили методы доступа getfamily(), gettype() и getproto() для получения значений семейства, типа и протокола для сокета.

  • Новый модуль: модуль spwd предоставляет функции для доступа к базе данных теневых паролей в системах, поддерживающих теневые пароли.

  • struct теперь работает быстрее, потому что он компилирует строки формата в объекты Struct с помощью методов pack() и unpack(). Это похоже на то, как модуль re позволяет создавать скомпилированные объекты регулярных выражений. Вы по-прежнему можете использовать функции уровня модуля pack() и unpack(); они будут создавать объекты Struct и кэшировать их. Или вы можете напрямую использовать экземпляры Struct:

    s = struct.Struct('ih3s')
    
    data = s.pack(1972, 187, 'abc')
    year, number, name = s.unpack(data)
    

    Вы также можете упаковывать и распаковывать данные в буферные объекты и из них напрямую, используя методы pack_into(buffer, offset, v1, v2, ...) и unpack_from(buffer, offset). Это позволяет хранить данные непосредственно в массиве или в отображаемом в память файле.

    (Объекты Struct были реализованы Бобом Ипполито во время спринта NeedForSpeed. Поддержка объектов буфера была добавлена Мартином Блейсом также во время спринта NeedForSpeed.)

  • Разработчики Python перешли с CVS на Subversion в процессе разработки версии 2.5. Информация о точной версии сборки доступна в виде переменной sys.subversion, состоящей из трех кортежей (interpreter-name, branch- name, revision-range). Например, на момент написания моя копия 2.5 сообщала ('CPython', 'trunk', '45313:45315').

    Информация также доступна для расширений C через функцию Py_GetBuildInfo(), которая возвращает строку информации о сборке, например: "trunk:45355:45356M, Apr 13 2006, 07:42:19". (Предоставлено Барри Варшавой.)

  • Другая новая функция, sys._current_frames(), возвращает текущие фреймы стека для всех запущенных потоков в виде словаря, отображающего идентификаторы потоков на самый верхний фрейм стека, активный в данный момент в этом потоке во время вызова функции. (Предоставлено Тимом Питерсом.)

  • Класс TarFile в модуле tarfile теперь имеет метод extractall(), который извлекает все элементы из архива в текущий рабочий каталог. Также можно установить другой каталог в качестве цели извлечения и распаковать только подмножество членов архива.

    Сжатие, используемое для tar-файла, открытого в потоковом режиме, теперь может определяться автоматически с использованием режима 'r|*'. (Предоставлено Ларсом Густебелем.)

  • Модуль threading теперь позволяет вам устанавливать размер стека, используемый при создании новых потоков. Функция stack_size([*size*]) возвращает текущий сконфигурированный размер стека, а предоставление дополнительного параметра size устанавливает новое значение. Не все платформы поддерживают изменение размера стека, но Windows, многопоточность POSIX и OS/2 поддерживают это. (Предоставлено Эндрю Макинтайром.)

  • Модуль unicodedata был обновлен для использования версии 4.1.0 базы данных символов Юникод. Версия 3.2.0 требуется некоторыми спецификациями, поэтому она по-прежнему доступна как unicodedata.ucd_3_2_0.

  • Новый модуль: модуль uuid генерирует универсальные уникальные идентификаторы (UUID) в соответствии с RFC 4122. RFC определяет несколько разных версий UUID, которые генерируются из исходной строки, из системных свойств или чисто случайным образом. Данный модуль содержит класс UUID и функции с именами uuid1(), uuid3(), uuid4() и uuid5() для создания различных версий UUID. (UUID версии 2 не указаны в RFC 4122 и не поддерживаются этим модулем.)

    >>> import uuid
    >>> # сделать UUID на основе идентификатора хоста и текущего времени
    >>> uuid.uuid1()
    UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
    
    >>> # создать UUID, используя хэш MD5 UUID пространства имён и имя
    >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
    UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
    
    >>> # сделать случайный UUID
    >>> uuid.uuid4()
    UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
    
    >>> # создать UUID, используя хэш SHA-1 UUID пространства имён и имя
    >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
    UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
    

    (Предоставлено Ка-Пинг Йи.)

  • Типы WeakKeyDictionary и WeakValueDictionary модуля weakref получили новые методы для перебора слабых ссылок, содержащихся в словаре. Методы iterkeyrefs() и keyrefs() были добавлены к WeakKeyDictionary, а методы itervaluerefs() и valuerefs() были добавлены к WeakValueDictionary. (Предоставлено Фредом Л. Дрейком-младшим.)

  • Модуль webbrowser получил ряд улучшений. Теперь его можно использовать как сценарий с python -m webbrowser, принимая URL-адрес в качестве аргумента; есть ряд переключателей для управления поведением (-n для нового окна браузера, -t для нового таба). Для поддержки этого были добавлены новые функции уровня модуля, open_new() и open_new_tab(). Функция модуля open() поддерживает дополнительный параметр autoraise сигнализирующий, поднимать ли открытое окно, когда это возможно. В список поддерживаемых был добавлен ряд дополнительных браузеров, например Firefox, Opera, Konqueror и elinks. (Предоставлено Олегом Бройтманном и Георгом Брандлом.)

  • Модуль xmlrpclib теперь поддерживает возвращение объектов datetime для типа даты XML-RPC. Предоставьте use_datetime=True функции loads() или классу Unmarshaller, чтобы включить эту функцию. (Предоставлено Скипом Монтанаро.)

  • Модуль zipfile теперь поддерживает версию формата ZIP64, а это означает, что ZIP-архив теперь может иметь размер более 4 ГБ и может содержать отдельные файлы размером более 4 ГБ. (Предоставлено Рональдом Оссореном.)

  • Объекты Compress и Decompress модуля zlib теперь поддерживают метод copy(), который создаёт копию внутреннего состояния объекта и возвращает новый объект Compress или Decompress. (Предоставлено Крисом Этли.)

Пакет ctypes

Пакет ctypes, написанный Томасом Хеллером, добавлен в стандартную библиотеку. ctypes позволяет вызывать произвольные функции в разделяемых библиотеках или DLL. Давние пользователи могут помнить модуль dl, предоставляющий функции для загрузки разделяемых библиотек и вызова в них функций. Пакет ctypes намного интереснее.

Чтобы загрузить общую библиотеку или библиотеку DLL, необходимо создать экземпляр класса CDLL и указать имя или путь к общей библиотеке или библиотеке DLL. После этого вы можете вызывать произвольные функции, обращаясь к ним как к атрибутам объекта CDLL.

import ctypes

libc = ctypes.CDLL('libc.so.6')
result = libc.printf("Line of output\n")

Предоставляются конструкторы типов для различных типов C: c_int(), c_float(), c_double(), c_char_p() (эквивалентно char *) и т. д. В отличие от типов Python, все версии C изменяемы; вы можете назначить их атрибуту value, чтобы изменить обернутое значение. Целые числа и строки Python будут автоматически преобразованы в соответствующие типы C, но для других типов вы должны вызвать правильный конструктор типа. (И я имею в виду must; неправильный выбор часто приводит к сбою интерпретатора из-за ошибки сегментации.)

Вы не должны использовать c_char_p() со строкой Python, когда функция C будет изменять область памяти, потому что строки Python должны быть неизменяемыми; нарушение этого правила вызовет загадочные ошибки. Если вам нужна изменяемая область памяти, используйте create_string_buffer():

s = "this is a string"
buf = ctypes.create_string_buffer(s)
libc.strfry(buf)

Предполагается, что функции C возвращают целые числа, но вы можете установить атрибут restype объекта функции, чтобы изменить это:

>>> libc.atof('2.71828')
-1783957616
>>> libc.atof.restype = ctypes.c_double
>>> libc.atof('2.71828')
2.71828

ctypes также предоставляет оболочку для Python C API в виде объекта ctypes.pythonapi. Данный объект not освобождает глобальную блокировку интерпретатора перед вызовом функции, потому что блокировка должна удерживаться при вызове кода интерпретатора. Существует конструктор типа py_object(), который создаст указатель PyObject *. Простое использование:

import ctypes

d = {}
ctypes.pythonapi.PyObject_SetItem(ctypes.py_object(d),
          ctypes.py_object("abc"),  ctypes.py_object(1))
# d is now {'abc', 1}.

Не забудьте использовать py_object(); если он пропущен, вы получить ошибку сегментации.

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

См.также

http://starship.python.net/crew/theller/ctypes/
Веб-страница ctypes с учебным пособием, справочником и часто задаваемыми вопросами.

Документация для модуля ctypes.

Пакет ElementTree

Подмножество библиотеки ElementTree Фредрика Лунда для обработки XML было добавлено в стандартную библиотеку как xml.etree. Доступные модули: ElementTree, ElementPath и ElementInclude из ElementTree 1.2.6. Также включён модуль ускорителя cElementTree.

В оставшейся части этого раздела будет представлен краткий обзор использования ElementTree. Полная документация по ElementTree доступна по адресу http://effbot.org/zone/element-index.htm.

ElementTree представляет XML-документ в виде дерева узлов элементов. Текстовое содержимое документа хранится в виде атрибутов text и tail (это одно из основных различий между ElementTree и объектной моделью документа; в DOM существует множество различных типов узлов, включая TextNode.)

Наиболее часто используемая функция синтаксического анализа — parse(), которая принимает либо строку (предположительно содержащую имя файла), либо файлоподобный объект и возвращает экземпляр ElementTree:

from xml.etree import ElementTree as ET

tree = ET.parse('ex-1.xml')

feed = urllib.urlopen(
          'http://planet.python.org/rss10.xml')
tree = ET.parse(feed)

Получив экземпляр ElementTree, вы можете вызвать его метод getroot(), чтобы получить корневой узел Element.

Также есть функция XML(), которая принимает строковый литерал и возвращает узел Element (не ElementTree). Данная функция обеспечивает аккуратный способ включения фрагментов XML, приближаясь по удобству к литералу XML:

svg = ET.XML("""<svg width="10px" version="1.0">
             </svg>""")
svg.set('height', '320px')
svg.append(elem1)

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

Операция Результат
elem[n] Возвращает n-й дочерний элемент.
elem[m:n] Возвращает список дочерних элементов с m-го по n-й.
len(elem) Возвращает количество дочерних элементов.
list(elem) Возвращает список дочерних элементов.
elem.append(elem2) Добавляет elem2 как дочерний.
elem.insert(index, elem2) Вставляет elem2 в указанное место.
del elem[n] Удаляет n-й дочерний элемент.
elem.keys() Возвращает список имён атрибутов.
elem.get(name) Возвращает значение атрибута name.
elem.set(name, value) Задаёт новое значение атрибута name.
elem.attrib Извлекает словарь, содержащий атрибуты.
del elem.attrib[name] Удаляет атрибут name.

Комментарии и инструкции по обработке также представлены как узлы Element. Чтобы проверить, является ли узел комментарием или оператором по обработке:

if elem.tag is ET.Comment:
    ...
elif elem.tag is ET.ProcessingInstruction:
    ...

Чтобы сгенерировать вывод XML, вы должны вызвать метод ElementTree.write(). Как и parse(), он может принимать либо строку, либо файловый объект:

# Кодировка в US-ASCII
tree.write('output.xml')

# Кодировка - UTF-8
f = open('output.xml', 'w')
tree.write(f, encoding='utf-8')

(Внимание: по умолчанию для вывода используется кодировка ASCII. Для общей работы с XML, когда имя элемента может содержать произвольные символы Юникод, ASCII не очень полезная кодировка, поскольку она вызовет исключение, если имя элемента содержит какие-либо символы со значениями. больше 127. Поэтому лучше указать другую кодировку, такую как UTF-8, которая может обрабатывать любой символ Юникод.)

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

См.также

http://effbot.org/zone/element-index.htm
Официальная документация для ElementTree.

Пакет hashlib

Новый модуль hashlib, написанный Грегори П. Смитом, был добавлен для замены модулей md5 и sha. hashlib добавляет поддержку дополнительных безопасных хэшей (SHA-224, SHA-256, SHA-384 и SHA-512). Если модуль доступен, он использует OpenSSL для быстрой реализации алгоритмов, оптимизированных для платформы.

Старые модули md5 и sha все ещё существуют как оболочки вокруг hashlib для сохранения обратной совместимости. Интерфейс нового модуля очень близок к интерфейсу старых модулей, но не идентичен. Самое существенное отличие состоит в том, что функции-конструкторы для создания новых объектов хэширования называются по-разному.

# Старые версии
h = md5.md5()
h = md5.new()

# Новая версия
h = hashlib.md5()

# Старые версии
h = sha.sha()
h = sha.new()

# Новая версия
h = hashlib.sha1()

# Хэш, которого раньше не было
h = hashlib.sha224()
h = hashlib.sha256()
h = hashlib.sha384()
h = hashlib.sha512()

# Альтернативная форма
h = hashlib.new('md5')          # Предоставьте алгоритм в виде строки

После создания хеш-объекта его методы остаются такими же, как и раньше: update(string) хэширует указанную строку в текущее состояние дайджеста, digest() и hexdigest() возвращают значение дайджеста в виде двоичной строки или строки шестнадцатеричных цифр, а copy() возвращает новый хэш-объект с тем же состоянием дайджеста.

См.также

Документация для модуля hashlib.

Пакет sqlite3

Модуль pysqlite (http://www.pysqlite.org), оболочка для встроенной базы данных SQLite, был добавлен в стандартную библиотеку под именем пакета sqlite3.

SQLite — это библиотека C, которая предоставляет облегченную базу данных на диске, не требующую отдельного серверного процесса и позволяющую обращаться к базе данных с помощью нестандартного варианта языка запросов SQL. Некоторые приложения могут использовать SQLite для внутреннего хранения данных. Также можно создать прототип приложения с помощью SQLite, а затем перенести код в более крупную базу данных, такую как PostgreSQL или Oracle.

pysqlite был написан Герхардом Херингом и предоставляет интерфейс SQL, совместимый со спецификацией DB-API 2.0, описанной в PEP 249.

Если вы компилируете исходный код Python самостоятельно, обратите внимание, что исходное дерево не включает код SQLite, а только модуль-оболочку. Вам нужно будет установить библиотеки и заголовочные файлы SQLite перед компиляцией Python, и процесс сборки скомпилирует модуль, когда будут доступны необходимые заголовочные файлы.

Чтобы использовать модуль, вы должны сначала создать объект Connection, представляющий базу данных. Здесь данные будут храниться в файле /tmp/example:

conn = sqlite3.connect('/tmp/example')

Вы также можете указать специальное имя :memory: для создания базы данных в оперативной памяти.

Получив Connection, вы можете создать объект Cursor и вызвать его метод execute() для выполнения команд SQL:

c = conn.cursor()

# Создать таблицу
c.execute('''create table stocks
(date text, trans text, symbol text,
 qty real, price real)''')

# Вставить строку данных
c.execute("""insert into stocks
          values ('2006-01-05','BUY','RHAT',100,35.14)""")

Обычно ваши операции SQL должны использовать значения из переменных Python. Вы не должны собирать свой запрос, используя строковые операции Python, потому что это небезопасно; это делает вашу программу уязвимой для атаки SQL-инъекцией.

Вместо этого используйте подстановку параметров DB-API. Поместите ? в качестве заполнителя везде, где вы хотите использовать значение, а затем указать кортеж значений в качестве второго аргумента для метода курсора execute(). (Другие модули базы данных могут использовать другой заполнитель, например %s или :1.) Например:

# Никогда не делайте этого --- небезопасно!
symbol = 'IBM'
c.execute("... where symbol = '%s'" % symbol)

# Сделайте это вместо этого
t = (symbol,)
c.execute('select * from stocks where symbol=?', t)

# Большой пример
for t in (('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
          ('2006-04-05', 'BUY', 'MSOFT', 1000, 72.00),
          ('2006-04-06', 'SELL', 'IBM', 500, 53.00),
         ):
    c.execute('insert into stocks values (?,?,?,?,?)', t)

Чтобы получить данные после выполнения инструкции SELECT, вы можете рассматривать курсор как итератор, вызывать метод курсора fetchone() для получения одной совпадающей строки или вызывать fetchall() для получения списка совпадающих строк.

В этом примере используется форма итератора:

>>> c = conn.cursor()
>>> c.execute('select * from stocks order by price')
>>> for row in c:
...    print row
...
(u'2006-01-05', u'BUY', u'RHAT', 100, 35.140000000000001)
(u'2006-03-28', u'BUY', u'IBM', 1000, 45.0)
(u'2006-04-06', u'SELL', u'IBM', 500, 53.0)
(u'2006-04-05', u'BUY', u'MSOFT', 1000, 72.0)
>>>

Дополнительные сведения о диалекте SQL, поддерживаемом SQLite, см. на странице https://www.sqlite.org.

См.также

http://www.pysqlite.org
Веб-страница pysqlite.
https://www.sqlite.org
Веб-страница SQLite; документация определяет синтаксис и доступные типы данных для поддерживаемого диалекта SQL.

Документация для модуля sqlite3.

PEP 249 — Спецификация API базы данных 2.0
PEP, написанный Марком-Андре Лембургом.

Пакет wsgiref

Интерфейс шлюза веб-сервера (WSGI) версии 1.0 определяет стандартный интерфейс между веб-серверами и веб-приложениями Python и описан в PEP 333. Пакет wsgiref является эталонной реализацией спецификации WSGI.

Пакет включает в себя базовый HTTP-сервер, на котором будет выполняться приложение WSGI; данный сервер полезен для отладки, но не предназначен для использования в производстве. Настройка сервера занимает всего несколько строк кода:

from wsgiref import simple_server

wsgi_app = ...

host = ''
port = 8000
httpd = simple_server.make_server(host, port, wsgi_app)
httpd.serve_forever()

См.также

http://www.wsgi.org
Центральный веб-сайт для ресурсов, связанных с WSGI.
PEP 333 — Интерфейс шлюза веб-сервера Python v1.0
PEP, написанный Филиппом Дж. Эби.

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

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

  • Исходное дерево Python было преобразовано из CVS в Subversion в ходе сложной процедуры миграции, которую контролировал и безукоризненно выполнил Мартин фон Лёвис. Процедура была разработана как PEP 347.

  • Компания Coverity, которая продает инструмент для анализа исходного кода Prevent, предоставила результаты исследования исходного кода Python. В ходе анализа было обнаружено около 60 ошибок, которые были оперативно исправлены. Многие из ошибок были связаны с проблемами подсчета ссылок, часто возникающими в коде обработки ошибок. См. https://scan.coverity.com для статистики.

  • Самое большое изменение в C API произошло от PEP 353, который модифицирует интерпретатор для использования определения типа Py_ssize_t вместо int. Обсуждение этого изменения см. в предыдущем разделе PEP 353: Использование ssize_t в качестве типа индекса.

  • Дизайн компилятора байт-кода сильно изменился, он больше не генерирует байт-код путём обхода дерева синтаксического анализа. Вместо этого дерево синтаксического анализа преобразуется в абстрактное синтаксическое дерево (или AST), и именно абстрактное синтаксическое дерево используется для создания байт-кода.

    Код Python может получить объекты AST, используя встроенный compile() и указав _ast.PyCF_ONLY_AST в качестве значения параметра flags:

    from _ast import PyCF_ONLY_AST
    ast = compile("""a=0
    for i in range(10):
        a += i
    """, "<string>", 'exec', PyCF_ONLY_AST)
    
    assignment = ast.body[0]
    for_loop = ast.body[1]
    

    Официальная документация для кода AST ещё не написана, но PEP 339 обсуждает дизайн. Чтобы начать изучение кода, прочитайте определение различных узлов AST в Parser/Python.asdl. Сценарий Python читает данный файл и создаёт множество определений структуры C в Include/Python-ast.h. PyParser_ASTFromString() и PyParser_ASTFromFile(), определённые в Include/pythonrun.h, принимают исходный код Python в качестве входных данных и возвращают корень AST, представляющий содержимое. Затем данный AST можно превратить в объект кода с помощью PyAST_Compile(). Для получения дополнительной информации прочитайте исходный код, а затем задаёт вопросы на python-dev.

    Код AST был разработан под руководством Джереми Хилтона и реализован (в алфавитном порядке) Бреттом Кэнноном, Ником Когланом, Грантом Эдвардсом, Джоном Эресманом, Куртом Кайзером, Нилом Норвицем, Тимом Питерсом, Армином Риго и Нилом Шеменауэром, а также участниками ряд спринтов AST на конференциях PyCon.

  • Был применен патч Эвана Джонса для obmalloc, впервые описанный в докладе на PyCon DC 2005. Python 2.4 выделял небольшие объекты на аренах размером 256 КБ, но никогда не освобождал арены. С этим патчем Python будет освобождать арены, когда они пусты. Чистый эффект заключается в том, что на некоторых платформах, когда вы выделяете много объектов, использование памяти Python может фактически снизиться при их удалении, и память может быть возвращена операционной системе. (Реализовано Эваном Джонсом и переработано Тимом Питерсом)

    Обратите внимание, что это изменение означает, что модули расширения должны быть более осторожными при распределении памяти. API Python имеет множество различных функций для выделения памяти, сгруппированных в семейства. Например, PyMem_Malloc(), PyMem_Realloc() и PyMem_Free() — это одно семейство, выделяющие необработанную память, а PyObject_Malloc(), PyObject_Realloc() и PyObject_Free() — другое семейство, предполагаемое для создания объектов Python.

    Ранее все данные разные семейства сводились к функциям платформы malloc() и free(). Это означало, что не имело значения, если вы ошиблись и выделили память с помощью функции PyMem(), но освободили её с помощью функции PyObject(). С изменениями obmalloc в версии 2.5 данные семейства теперь делают разные вещи, и несоответствия, вероятно, приведут к segfault. Вы должны тщательно протестировать свои модули расширения C с помощью Python 2.5.

  • Встроенные типы множеств теперь имеют официальный C API. Вызвать PySet_New() и PyFrozenSet_New(), чтобы создать новый множество, PySet_Add() и PySet_Discard(), чтобы добавить и удалить элементы, и PySet_Contains() и PySet_Size(), чтобы проверить состояние набора. (Предоставлено Рэймондом Хеттингером.)

  • Код C теперь может получить информацию о точной версии интерпретатора Python, вызвав функцию Py_GetBuildInfo(), которая возвращает строку информации о сборке, например: "trunk:45355:45356M, Apr 13 2006, 07:42:19". (Предоставлено Барри Варшавой.)

  • Два новых макроса можно использовать для указания функций C, которые являются локальными для текущего файла, чтобы можно было использовать более быстрое соглашение о вызовах. Py_LOCAL(type) объявляет функцию как возвращающую значение указанного type и использует квалификатор быстрого вызова. Py_LOCAL_INLINE(type) делает то же самое и также запрашивает встраивание функции. Если PY_LOCAL_AGGRESSIVE() определён до включения python.h, для модуля включается множество более агрессивных оптимизаций; вам следует сравнить результаты, чтобы выяснить, действительно ли данные оптимизации делают код быстрее. (Предоставил Фредрик Лунд на спринте NeedForSpeed.)

  • PyErr_NewException(name, base, dict) теперь может принимать кортеж базовых классов в качестве аргумента base. (Предоставлено Георгом Брандлом)

    Функция PyErr_Warn() для выдачи предупреждений теперь устарела в пользу PyErr_WarnEx(category, message, stacklevel), которая позволяет указать количество фреймов стека, разделяющих эту функцию и вызывающую программу. stacklevel, равный 1, — это функция, вызывающая PyErr_WarnEx(), 2 — это функция над ней и так далее. (Добавлено Нилом Норвицем)

  • Интерпретатор CPython по-прежнему написан на C, но код теперь можно компилировать с помощью компилятора C++ без ошибок. (Реализовано Энтони Бакстером, Мартином фон Лёвисом, Скипом Монтанаро)

  • Функция PyRange_New() удалена. Он никогда не был задокументирован, никогда не использовался в основном коде и имел опасно слабую проверку ошибок. В маловероятном случае, если ваши расширения использовали его, вы можете заменить его чем-то вроде следующего:

    range = PyObject_CallFunction((PyObject*) &PyRange_Type, "lll",
                                  start, stop, step);
    

Изменения для портов

  • MacOS X (10.3 и выше): динамическая загрузка модулей теперь использует функцию dlopen() вместо функций, специфичных для MacOS.
  • MacOS X: в скрипт configure добавлен переключатель -- enable-universalsdk, который компилирует интерпретатор как универсальный двоичный файл, способный работать как на процессорах PowerPC, так и на процессорах Intel. (Предоставлено Рональдом Уссореном; bpo-2573.)
  • Windows: .dll больше не поддерживается в качестве расширения имени файла для модулей расширения. .pyd теперь единственное расширение имени файла, которое будет искаться.

Портирование на Python 2.5

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

  • ASCII теперь является кодировкой по умолчанию для модулей. Теперь это синтаксическая ошибка, если модуль содержит строковые литералы с 8-битными символами, но не имеет объявления кодировки. В Python 2.4 это вызвало предупреждение, а не синтаксическую ошибку.
  • Ранее атрибут генератора gi_frame всегда был объектом фрейма. Из-за изменений PEP 342, описанных в разделе PEP 342: Новые функции генератора, теперь gi_frame может быть None.
  • Новое предупреждение UnicodeWarning выдается при попытке сравнить строку Юникод и 8-битную строку, которую нельзя преобразовать в Юникод с использованием кодировки ASCII по умолчанию. Раньше такие сравнения вызывали исключение UnicodeDecodeError.
  • Библиотека: модуль csv теперь более строго относится к многострочным полям в кавычках. Если ваши файлы содержат новые строки, встроенные в поля, ввод должен быть разбит на строки таким образом, чтобы сохранить символы новой строки.
  • Библиотека: функция format() модуля locale ранее принимала любую строку, если появлялось не более одного спецификатора %char. В Python 2.5 аргумент должен быть ровно одним спецификатором %char без окружающего текста.
  • Библиотека: модули pickle и cPickle больше не принимают возвращаемое значение None из метода __reduce__(); вместо этого метод должен возвращать кортеж аргументов. Модули также больше не принимают устаревший ключевой параметр bin.
  • Библиотека: классы SimpleXMLRPCServer и DocXMLRPCServer теперь имеют атрибут rpc_paths, ограничивающий операции XML-RPC ограниченным набором URL-адресов; по умолчанию разрешены только '/' и '/RPC2'. Установка rpc_paths в None или пустой кортеж отключает эту проверку пути.
  • C API: многие функции теперь используют Py_ssize_t вместо int, что позволяет обрабатывать больше данных на 64-разрядных машинах. В коде расширения может потребоваться внести такое же изменение, чтобы избежать предупреждений и обеспечить поддержку 64-разрядных машин. Обсуждение этого изменения см. в предыдущем разделе PEP 353: Использование ssize_t в качестве типа индекса.
  • C API: изменения obmalloc означают, что вы должны быть осторожны, чтобы не смешивать использование семейств функций PyMem_*() и PyObject_*(). Память, выделенная с помощью *_Malloc() одного семейства, должна быть освобождена с помощью функции *_Free() соответствующего семейства.

Благодарности

Автор хотел бы поблагодарить следующих людей за предложения, исправления и помощь с различными черновиками этой статьи: Георга Брандла, Ника Коглана, Филиппа Дж. Эби, Ларса Густебеля, Рэймонда Хеттингера, Ральфа В. Гроссе- Кунстлеве, Кента Джонсона, Иэн Лоу, Мартин фон Лёвис, Фредрик Лунд, Эндрю Макнамара, Скип Монтанаро, Густаво Нимейер, Пол Прескод, Джеймс Прайор, Майк Ровнер, Скотт Вайкарт, Барри Уоршан, Томас Воутерс.