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

Автор

А.М. Кучлинг

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

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

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

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

Эта статья не претендует на полное описание новых возможностей; вместо этого изменения кратко представлены на полезных примерах. За полной информацией всегда следует обращаться к документации по Python 2.5 на сайте https://docs.python.org. Если вы хотите понять полную реализацию и обоснование дизайна, обратитесь к PEP для конкретной новой функции.

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

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

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

if condition:
    x = true_value
else:
    x = false_value

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

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

x = true_value if condition else false_value

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

Этот синтаксис может показаться странным и обратным; почему условие находится в середине выражения, а не впереди, как в c ? x : y в Си? Это решение было проверено путем применения нового синтаксиса к модулям стандартной библиотеки и просмотра того, как читается полученный код. Во многих случаях, когда используется условное выражение, одно значение кажется «обычным случаем», а другое - «исключительным случаем», используемым только в редких случаях, когда условие не выполняется. Синтаксис условного выражения делает эту схему более очевидной:

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

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

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

# First version -- no parens
level = 1 if logging else 0

# Second version -- with parens
level = (1 if logging else 0)

В первой версии, я думаю, глаз читателя может сгруппировать утверждение в „level = 1“, „if logging“, „else 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). Полученный объект является вызываемым, поэтому вы можете просто вызвать его, чтобы вызвать функцию с заполненными аргументами.

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

import functools

def log (message, subsystem):
    "Write the contents of 'message' to the specified subsystem."
    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() копирует имя, модуль и атрибут 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 предоставляет более аккуратный способ выполнения импорта из стандартной библиотеки, 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:

# Import names from pkg.string
from .string import name1, name2
# Import pkg.string
from . import string

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

from . import D                 # Imports A.B.D
from .. import E                # Imports A.E
from ..F import G               # Imports A.F.G

Опережающие периоды не могут использоваться с формой import modname оператора импорта, только с формой from ... import.

См.также

PEP 328 - Импорт: Многострочный и абсолютный/относительный

PEP написан Aahz; реализован Thomas Wouters.

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

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

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

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

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

См.также

PEP 341 - Унификация try-except и try-finally

PEP написан Георгом Брандлом; реализация Томасом Ли.

PEP 342: Новые возможности генератора

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

В 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 возвращает указанное значение. Если вызывается регулярный метод next(), то yield возвращает None.

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

def counter (maximum):
    i = 0
    while i < maximum:
        val = (yield i)
        # If value provided, change counter
        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 Раймондом Хеттингером и PEP 325 Самуэле Педрони.

https://en.wikipedia.org/wiki/Coroutine

Запись в Википедии о корутинах.

https://web.archive.org/web/20160321211320/http://www.sidhe.org/~dan/blog/archives/000178.html

Объяснение корутинов с точки зрения Perl, написанное Дэном Шугальски.

PEP 343: Заявление „с“

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

Оператор „with“ представляет собой новую структуру потока управления, базовой структурой которой является:

with expression [as variable]:
    with-block

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

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

После завершения выполнения with-блока вызывается метод __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
        ... more processing code ...

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

Примечание

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

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

lock = threading.Lock()
with lock:
    # Critical section of code
    ...

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

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

from decimal import Decimal, Context, localcontext

# Displays with default precision of 28 digits
v = Decimal('578')
print v.sqrt()

with localcontext(Context(prec=16)):
    # All code in this block uses a precision of 16 digits.
    # The original context is restored on exiting the block.
    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 ...')
    # ... more operations ...

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

class DatabaseConnection:
    # Database interface
    def cursor (self):
        "Returns a cursor object and starts a new transaction"
    def commit (self):
        "Commits current transaction"
    def rollback (self):
        "Rolls back current transaction"

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

class DatabaseConnection:
    ...
    def __enter__ (self):
        # Code to start a new transaction
        cursor = self.cursor()
        return cursor

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

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

class DatabaseConnection:
    ...
    def __exit__ (self, type, value, tb):
        if tb is None:
            # No exception, so commit
            self.commit()
        else:
            # Exception occurred, so rollback.
            self.rollback()
            # return False

Модуль contextlib

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

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

PEP, написанный Гвидо ван Россумом и Ником Когланом; реализован Майком Бландом, Гвидо ван Россумом и Нилом Норвицем. PEP показывает код, сгенерированный для оператора „with“, что может быть полезно для изучения того, как работает этот оператор.

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

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

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

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

BaseException       # New in Python 2.5
|- KeyboardInterrupt
|- SystemExit
|- Exception
   |- (all other current built-in exceptions)

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

try:
    ...
except (KeyboardInterrupt, SystemExit):
    raise
except:
    # Log error...
    # Continue running program...

В 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 в качестве типа индекса

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

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

Ограничение в 2147483647 элементов не имеет значения на 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. Функции PyArg_ParseTuple() s# и t# по-прежнему выводят 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 был добавлен в структуру C-уровня PyNumberMethods, чтобы позволить расширениям 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
    
  • Тип partition(sep) имеет новый крючок, позволяющий подклассам предоставлять значение по умолчанию, когда ключ не содержится в словаре. Когда ключ не найден, будет вызван метод словаря rpartition(sep). Этот хук используется для реализации нового класса в модуле . Следующий пример определяет словарь, который возвращает ноль для любого отсутствующего ключа:

    Метод find(S) часто используется для получения индекса, который затем используется для разрезания строки и получения частей, находящихся до и после разделителя. partition(sep) сводит эту схему к одному вызову метода, который возвращает кортеж, содержащий подстроку перед разделителем, сам разделитель и подстроку после разделителя. Если разделитель не найден, то первым элементом кортежа будет вся строка, а два других элемента будут пустыми. 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']
    # Prints 'longest'
    print max(L, key=len)
    # Prints 'short', because lexicographically 'short' has the largest value
    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 по умолчанию. Результатом сравнения является false:

    >>> chr(128) == unichr(128)   # Can't convert chr(128) to Unicode
    __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) can be converted
    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. По умолчанию это предупреждение молча игнорируется; чтобы отобразить предупреждение, при запуске исполняемого файла Python укажите опцию -Wd. (Реализовано Томасом Воутерсом.)

  • (Выполнено Марком-Андре Лембургом.)

    class C():
        pass
    

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

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

В интерактивном интерпретаторе 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 внутренняя структура данных была адаптирована для реализации множеств, в результате чего множества будут использовать на треть меньше памяти и работать несколько быстрее. (Реализовано Раймондом Хеттингером.)

  • Улучшена скорость выполнения некоторых операций Unicode, таких как поиск подстрок, разбиение строк, кодирование и декодирование карты символов. (Улучшения поиска подстрок и разбиения были добавлены Фредриком Лундом и Эндрю Дальке в ходе спринта 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), который удаляет первое вхождение значения в очереди, выдавая сообщение ValueError, если значение не найдено. (Внесено Раймондом Хеттингером.)

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

  • Новый модуль: Модуль cProfile представляет собой реализацию на языке Си существующего модуля profile, имеющего гораздо меньшие накладные расходы. Интерфейс модуля такой же, как и у profile: вы запускаете cProfile.run('main()') для профилирования функции, можете сохранить данные профиля в файл и т.д. Пока неизвестно, будет ли профилировщик Hotshot, который также написан на C, но не имеет интерфейса модуля profile, поддерживаться в будущих версиях 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, которая не дает примеру выполняться вообще. Это предназначено для фрагментов кода, которые являются примерами использования, предназначенными для читателя, и не являются тестовыми примерами.

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

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

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

  • В модуле 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)  # Return two lowest elements, lexicographically
    ['longer still', 'longest']
    >>> heapq.nsmallest(2, L, key=len)   # Return two shortest elements
    ['short', 'medium']
    

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

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

    s = slice(5)     # Create slice object
    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' uses email.Message.Message as the class representing
    # individual messages.
    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(). (Внесено Беном Беллом.)

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

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

  • Модуль os претерпел несколько изменений. Переменная stat_float_times теперь по умолчанию имеет значение true, что означает, что 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, благодаря исправлению от Филиппа Бионди. Сокеты 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).

  • В процессе разработки 2.5 разработчики Python перешли с CVS на Subversion. Информация о точной версии сборки доступна в виде переменной sys.subversion, представляющей собой 3 кортежа из (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 threading и OS/2 поддерживают. (Внесено Эндрю Макинтайром.)

  • Модуль unicodedata был обновлен для использования версии 4.1.0 базы данных символов Unicode. Версия 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
    >>> # make a UUID based on the host ID and current time
    >>> uuid.uuid1()
    UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
    
    >>> # make a UUID using an MD5 hash of a namespace UUID and a name
    >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
    UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
    
    >>> # make a random UUID
    >>> uuid.uuid4()
    UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
    
    >>> # make a UUID using a SHA-1 hash of a namespace UUID and a name
    >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
    UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
    

    (При участии Ка-Пинг Йи.)

  • Типы weakref модуля WeakKeyDictionary и WeakValueDictionary получили новые методы для итерации по слабым ссылкам, содержащимся в словаре. Методы 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 Гб. (Внесено Рональдом Оусореном.)

  • Объекты zlib модуля Compress и Decompress теперь поддерживают метод 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, но для других типов вы должны вызвать конструктор правильного типа. (И я имею в виду должны; неправильный вызов часто приводит к аварийному завершению интерпретатора с ошибкой сегментации).

Вы не должны использовать 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 также предоставляет обертку для C API Python в виде объекта ctypes.pythonapi. Этот объект не освобождает глобальную блокировку интерпретатора перед вызовом функции, поскольку блокировка должна удерживаться при вызове кода интерпретатора. Существует конструктор типа 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.

См.также

https://web.archive.org/web/20180410025338/http://starship.python.net/crew/theller/ctypes/

Веб-страница pre-stdlib ctypes, содержащая учебник, справочник и FAQ.

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

Пакет ElementTree

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

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

ElementTree представляет XML-документ в виде дерева узлов элементов. Текстовое содержимое документа хранится в виде атрибутов text и tail (Это одно из основных различий между ElementTree и Document Object Model; в 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(), он может принимать либо строку, либо файлоподобный объект:

# Encoding is US-ASCII
tree.write('output.xml')

# Encoding is UTF-8
f = open('output.xml', 'w')
tree.write(f, encoding='utf-8')

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

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

См.также

https://web.archive.org/web/20201124024954/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 для сохранения обратной совместимости. Интерфейс нового модуля очень близок к интерфейсу старых модулей, но не идентичен. Наиболее существенным отличием является то, что функции конструктора для создания новых объектов хэширования называются по-другому.

# Old versions
h = md5.md5()
h = md5.new()

# New version
h = hashlib.md5()

# Old versions
h = sha.sha()
h = sha.new()

# New version
h = hashlib.sha1()

# Hash that weren't previously available
h = hashlib.sha224()
h = hashlib.sha256()
h = hashlib.sha384()
h = hashlib.sha512()

# Alternative form
h = hashlib.new('md5')          # Provide algorithm as a string

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

См.также

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

Пакет sqlite3

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

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

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

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

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

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

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

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

c = conn.cursor()

# Create table
c.execute('''create table stocks
(date text, trans text, symbol text,
 qty real, price real)''')

# Insert a row of data
c.execute("""insert into stocks
          values ('2006-01-05','BUY','RHAT',100,35.14)""")

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

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

# Never do this -- insecure!
symbol = 'IBM'
c.execute("... where symbol = '%s'" % symbol)

# Do this instead
t = (symbol,)
c.execute('select * from stocks where symbol=?', t)

# Larger example
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.

См.также

https://www.pysqlite.org

Веб-страница pysqlite.

https://www.sqlite.org

Веб-страница SQLite; документация описывает синтаксис и доступные типы данных для поддерживаемого диалекта SQL.

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

PEP 249 - Спецификация API базы данных 2.0

PEP написан Марком-Андре Лембургом.

Пакет wsgiref

Интерфейс шлюза веб-сервера (WSGI) v1.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()

См.также

https://web.archive.org/web/20160331090247/http://wsgi.readthedocs.org/en/latest/

Центральный веб-сайт для ресурсов, связанных с WSGI.

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

PEP, написанная Филиппом Дж. Эби.

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

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

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

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

  • Самое большое изменение в API языка C произошло в 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 читает этот файл и генерирует набор определений структур языка Си в 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 выделял небольшие объекты в аренах размером 256K, но никогда не освобождал арены. С этим патчем Python будет освобождать арены, когда они будут пусты. Чистый эффект заключается в том, что на некоторых платформах, когда вы выделяете много объектов, использование памяти Python может фактически уменьшиться при их удалении, а память может быть возвращена операционной системе. (Реализовано Эваном Джонсом и переработано Тимом Питерсом).

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

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

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

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

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

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

  • Функция PyErr_Warn() для выдачи предупреждений теперь устарела в пользу PyErr_WarnEx(category, message, 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: в сценарий --enable-universalsdk добавлен переключатель configure, который компилирует интерпретатор как универсальный двоичный файл, способный работать как на процессорах 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 теперь строже относится к многострочным полям с кавычками. Если ваши файлы содержат символы новой строки, встроенные в поля, ввод должен быть разделен на строки таким образом, чтобы сохранить символы новой строки.

  • Библиотека: функции locale модуля format() ранее принимали любую строку, если в ней было не более одного спецификатора %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 соответствующего семейства.

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

Автор хотел бы поблагодарить следующих людей за предложения, исправления и помощь в работе над различными черновиками этой статьи: Georg Brandl, Nick Coghlan, Phillip J. Eby, Lars Gustäbel, Raymond Hettinger, Ralf W. Grosse-Kunstleve, Kent Johnson, Iain Lowe, Martin von Löwis, Fredrik Lundh, Andrew McNamara, Skip Montanaro, Gustavo Niemeyer, Paul Prescod, James Pryor, Mike Rovner, Scott Weikart, Barry Warsaw, Thomas Wouters.

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