Что нового в Python 2.3

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

В этой статье объясняются новые возможности Python 2.3. Python 2.3 был выпущен 29 июля 2003 года.

Основными темами для Python 2.3 являются доработка некоторых функций, добавленных в версии 2.2, добавление различных небольших, но полезных улучшений в основной язык и расширение стандартной библиотеки. Новая объектная модель, представленная в предыдущей версии, выиграла от 18 месяцев исправлений ошибок и усилий по оптимизации, которые повысили производительность классов нового стиля. Добавлено несколько новых встроенных функций, таких, как sum() и enumerate(). Оператор in теперь можно использовать для поиска подстрок (например, "ab" in "abc" возвращает True).

Некоторые из многих новых функций библиотеки включают логические типы данных, множество, кучу и дату/время, возможность импорта модулей из архивов в формате ZIP, поддержку метаданных для долгожданного каталога Python, обновленную версию IDLE и модули. для регистрации сообщений, переноса текста, разбора CSV-файлов, обработки параметров командной строки, использования баз данных BerkeleyDB… список новых и усовершенствованных модулей очень длинный.

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

PEP 218: тип данных стандартного множества

Новый модуль sets содержит реализацию заданного типа данных. Класс Set предназначен для изменяемых наборов, наборов, в которые можно добавлять и удалять элементы. Класс ImmutableSet предназначен для наборов, которые нельзя изменить, поэтому экземпляры ImmutableSet можно использовать в качестве ключей словаря. Наборы строятся на основе словарей, поэтому элементы внутри набора должны быть хэшируемыми.

Вот простой пример:

>>> import sets
>>> S = sets.Set([1,2,3])
>>> S
Set([1, 2, 3])
>>> 1 in S
True
>>> 0 in S
False
>>> S.add(5)
>>> S.remove(3)
>>> S
Set([1, 2, 5])
>>>

Объединение и пересечение множеств можно вычислить с помощью методов union() и intersection(); в альтернативной записи используются побитовые операторы & и |. Изменяемые наборы также имеют версии данных методов на месте, union_update() и intersection_update().

>>> S1 = sets.Set([1,2,3])
>>> S2 = sets.Set([4,5,6])
>>> S1.union(S2)
Set([1, 2, 3, 4, 5, 6])
>>> S1 | S2                  # Альтернативное обозначение
Set([1, 2, 3, 4, 5, 6])
>>> S1.intersection(S2)
Set([])
>>> S1 & S2                  # Альтернативное обозначение
Set([])
>>> S1.union_update(S2)
>>> S1
Set([1, 2, 3, 4, 5, 6])
>>>

Также можно взять симметричную разность двух множеств. Это множество всех элементов объединения, не находящихся на пересечении. Другими словами, симметричная разность содержит все элементы, которые находятся ровно в одном множестве. Опять же, есть альтернативное обозначение (^) и встроенная версия с неуклюжим именем symmetric_difference_update().

>>> S1 = sets.Set([1,2,3,4])
>>> S2 = sets.Set([3,4,5,6])
>>> S1.symmetric_difference(S2)
Set([1, 2, 5, 6])
>>> S1 ^ S2
Set([1, 2, 5, 6])
>>>

Существуют также методы issubset() и issuperset() для проверки того, является ли один множество подмножеством или надмножеством другого:

>>> S1 = sets.Set([1,2,3])
>>> S2 = sets.Set([2,3])
>>> S2.issubset(S1)
True
>>> S1.issubset(S2)
False
>>> S1.issuperset(S2)
True
>>>

См.также

PEP 218 — Добавление встроенного типа объекта Set
PEP, написанный Грегом В. Уилсоном. Реализовано Грегом В. Уилсоном, Алексом Мартелли и ГвР.

PEP 255: Простые генераторы

В Python 2.2 генераторы были добавлены в качестве дополнительной функции, которая должна быть включена директивой from __future__ import generators. В версии 2.3 генераторы больше не нужно специально включать, и теперь они всегда присутствуют; это означает, что yield теперь всегда является ключевым словом. Остальная часть этого раздела является копией описания генераторов из документа «Что нового в Python 2.2»; если вы читали его, когда вышел Python 2.2, вы можете пропустить оставшуюся часть этого раздела.

Вы, несомненно, знакомы с тем, как вызовы функций работают в Python или C. Когда вы вызываете функцию, она получает частное пространство имён, в котором создаются её локальные переменные. Когда функция достигает оператора return, локальные переменные уничтожаются, а результирующее значение возвращается вызывающей стороне. Последующий вызов той же функции получит новое множество локальных переменных. Но что, если бы локальные переменные не сбрасывались при выходе из функции? Что, если бы вы могли позже возобновить функцию с того места, где она остановилась? Это то, что обеспечивают генераторы; их можно рассматривать как возобновляемые функции.

Вот простейший пример функции-генератора:

def generate_ints(N):
    for i in range(N):
        yield i

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

Когда вы вызываете функцию-генератор, она не возвращает ни одного значения; вместо этого он возвращает объект генератора, который поддерживает протокол итератора. При выполнении инструкции yield генератор выводит значение i, аналогичное инструкции return. Большая разница между операторами yield и return заключается в том, что при достижении yield состояние выполнения генератора приостанавливается, а локальные переменные сохраняются. При следующем вызове метода генератора .next() функция возобновит выполнение сразу после оператора yield. (По сложным причинам оператор yield не разрешен внутри блока try оператора tryfinally; прочитать PEP 255 для полного объяснения взаимодействия между yield и исключениями.)

Вот пример использования генератора generate_ints():

>>> gen = generate_ints(3)
>>> gen
<generator object at 0x8117f90>
>>> gen.next()
0
>>> gen.next()
1
>>> gen.next()
2
>>> gen.next()
Traceback (most recent call last):
  File "stdin", line 1, in ?
  File "stdin", line 2, in generate_ints
StopIteration

Вы также можете написать for i in generate_ints(5) или a,b,c = generate_ints(3).

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

Вы можете добиться эффекта генераторов вручную, написав свой собственный класс и сохранив все локальные переменные генератора как переменные экземпляра. Например, возвращает список целых чисел можно, установив для self.count значение 0, а метод next() увеличит self.count и вернёт его. Однако для умеренно сложного генератора написать соответствующий класс было бы гораздо сложнее. Lib/test/test_generators.py содержит ряд более интересных примеров. Самый простой из них реализует обход дерева по порядку с использованием генераторов рекурсивно.

# Рекурсивный генератор, который генерирует листья дерева по порядку.
def inorder(t):
    if t:
        for x in inorder(t.left):
            yield x
        yield t.label
        for x in inorder(t.right):
            yield x

Два других примера в Lib/test/test_generators.py дают решения проблемы N-ферзей (размещение $N$ ферзей на шахматной доске размером $NxN$, чтобы ни одна ферзь не угрожала другой) и рыцарского тура (маршрут, который ведёт коня на каждую клетку $ Шахматная доска NxN$ без посещения любой клетки дважды).

Идея генераторов пришла из других языков программирования, особенно из Icon (https://www.cs.arizona.edu/icon/), где идея генераторов является центральной. В Icon каждое выражение и вызов функции ведут себя как генератор. Один пример из «Обзора языка программирования Icon» на https://www.cs.arizona.edu/icon/docs/ipd266.htm дает представление о том, как это выглядит:

sentence := "Store it in the neighboring harbor"
if (i := find("or", sentence)) > 5 then write(i)

В Icon функция find() возвращает индексы, в которых встречается подстрока «или»: 3, 23, 33. В операторе if i сначала присваивается значение 3, но 3 меньше 5, поэтому сравнение не выполняется, и Icon повторяет попытку со вторым значением 23. 23 больше 5, поэтому теперь сравнение завершается успешно, и код выводит значение 23 на экран.

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

См.также

PEP 255 — Простые генераторы
Сценарий: Нил Шеменауэр, Тим Питерс, Магнус Ли Хетланд. Реализовано в основном Нила Шеменауэра и Тима Питерса, с другими исправлениями от команды Python Labs.

PEP 263: Кодировки исходного кода

Исходные файлы Python теперь могут быть объявлены в различных кодировках набора символов. Кодировки объявляются путём включения специально отформатированного комментария в первую или вторую строку исходного файла. Например, файл UTF-8 можно объявить с помощью:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

Без такого объявления кодировки по умолчанию используется 7-битная кодировка ASCII. Выполнение или импорт модулей, содержащих строковые литералы с 8-битными символами и не имеющих объявления кодировки, приведёт к тому, что Python 2.3 выдаст сигнал DeprecationWarning; в 2.4 это будет синтаксическая ошибка.

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

См.также

PEP 263 — Определение кодировок исходного кода Python
Написано Марк-Андре Лембург и Мартином фон Лёвисом; реализован Сузуки Хисао и Мартин фон Лоуис.

PEP 273: Импорт модулей из ZIP-архивов

Новый модуль zipimport добавляет поддержку импорта модулей из ZIP- архива. Вам не нужно явно импортировать модуль; он будет автоматически импортирован, если имя файла ZIP-архива будет добавлено к sys.path. Например:

amk@nyman:~/src/python$ unzip -l /tmp/example.zip
Archive:  /tmp/example.zip
  Length     Date   Time    Name
 --------    ----   ----    ----
     8467  11-26-02 22:30   jwzthreading.py
 --------                   -------
     8467                   1 file
amk@nyman:~/src/python$ ./python
Python 2.3 (#1, Aug 1 2003, 19:54:32)
>>> import sys
>>> sys.path.insert(0, '/tmp/example.zip')  # Add .zip file to front of path
>>> import jwzthreading
>>> jwzthreading.__file__
'/tmp/example.zip/jwzthreading.py'
>>>

Запись в sys.path теперь может быть именем файла ZIP-архива. ZIP-архив может содержать любые файлы, но можно импортировать только файлы с именами *.py, *.pyc или *.pyo. Если архив содержит только файлы *.py, Python не будет пытаться изменить архив, добавив соответствующий файл *.pyc, а это означает, что если ZIP-архив не содержит файлов *.pyc, импорт может быть довольно медленным.

Путь внутри архива также можно указать для импорта только из подкаталога; например, путь /tmp/example.zip/lib/ будет импортироваться только из подкаталога lib/ внутри архива.

См.также

PEP 273 — Импорт модулей из Zip-архивов
Написано Джеймсом С. Алстромом, который также предоставил реализацию. Питон 2.3 следует спецификации в PEP 273, но использует реализацию, написанную Просто van Rossum, который использует хуки импорта, описанные в PEP 302. См. раздел PEP 302: Новые хуки импорта для описания новых хуков импорта.

PEP 277: поддержка имени файла Юникод для Windows NT

В Windows NT, 2000 и XP система хранит имена файлов в виде строк Юникод. Традиционно Python представляет имена файлов в виде строк байтов, что неадекватно, поскольку делает некоторые имена файлов недоступными.

Python теперь позволяет использовать произвольные Юникод строки (в рамках ограничений файловой системы) для всех функций, которые ожидают имена файлов, в первую очередь для встроенной функции open(). Если строка Юникод передаётся в os.listdir(), Python теперь возвращает список строк Юникод. Новая функция os.getcwdu() возвращает текущий каталог в виде строки Юникод.

Строки байтов по-прежнему работают как имена файлов, и в Windows Python прозрачно преобразует их в Юникод, используя кодировку mbcs.

Другие системы также допускают использование строк Юникод в качестве имён файлов, но перед передачей в систему преобразуют их в строки байтов, что может привести к возникновению ошибки UnicodeError. Приложения могут проверять, поддерживаются ли произвольные строки Юникод в качестве имён файлов, проверяя os.path.supports_unicode_filenames, логическое значение.

В MacOS os.listdir() теперь может возвращать имена файлов в формате Юникод.

См.также

PEP 277 — поддержка имени файла Юникод для Windows NT
Автор Нил Ходжсон; реализован Нилом Ходжсоном, Мартином фон Лёвисом и Марком Хаммонд.

PEP 278: универсальная поддержка новой строки

Сегодня используются три основные операционные системы: Microsoft Windows, Apple Macintosh OS и различные производные Unix. Небольшое раздражение от кроссплатформенной работы заключается в том, что все данные три платформы используют разные символы для обозначения концов строк в текстовых файлах. Unix использует перевод строки (10-й символ ASCII), MacOS использует возврат каретки (13-й символ ASCII), а Windows использует последовательность из двух символов, состоящую из возврата каретки и новой строки.

Файловые объекты Python теперь могут поддерживать соглашения об окончании строки, отличные от используемых на данной платформе. Открытие файла с режимом 'U' или 'rU' откроет файл для чтения в режиме универсальный символ новой строки. Все три соглашения об окончании строки будут преобразованы в '\n' в строках, возвращаемых различными файловыми методами, такими как read() и readline().

Универсальная поддержка новой строки также используется при импорте модулей и при выполнении файла с функцией execfile(). Это означает, что модули Python могут совместно использоваться всеми тремя операционными системами без необходимости преобразования концов строк.

Эту функцию можно отключить при компиляции Python, указав переключатель --without-universal-newlines при запуске сценария Python configure.

См.также

PEP 278 — универсальная поддержка новой строки
Написано и реализовано Джеком Янсеном.

PEP 279: enumerate()

Новая встроенная функция enumerate() сделает некоторые циклы более четкими. enumerate(thing), где thing — это либо итератор, либо последовательность, возвращает итератор, который вернёт (0, thing[0]), (1, thing[1]), (2, thing[2]) и т. д.

Обычная идиома для изменения каждого элемента списка выглядит следующим образом:

for i in range(len(L)):
    item = L[i]
    # ... вычислить некоторый результат на основе элемента ...
    L[i] = result

Это можно переписать, используя enumerate() as:

for i, item in enumerate(L):
    # ... вычислить некоторый результат на основе элемента ...
    L[i] = result

См.также

PEP 279 — встроенная функция enumerate()
Написано и реализовано Рэймондом Д. Хеттингером.

PEP 282: пакет ведения журнала

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

Класс Logger является основным классом. Большая часть кода приложения будет иметь дело с одним или несколькими объектами Logger, каждый из которых используется определенной подсистемой приложения. Каждый Logger идентифицируется по имени, а имена организованы в иерархию с использованием . в качестве разделителя компонентов. Например, у вас могут быть экземпляры Logger с именами server, server.auth и server.network. Последние два экземпляра находятся ниже server в иерархии. Это означает, что если вы включает детализацию для server или направите сообщения server другому обработчику, изменения также будут применяться к записям, зарегистрированным в server.auth и server.network. Также есть корень Logger, который является родительским для всех других логгеров.

Для простого использования пакет logging содержит некоторые удобные функции, которые всегда используют корневой журнал:

import logging

logging.debug('Debugging information')
logging.info('Informational message')
logging.warning('Warning:config file %s not found', 'server.conf')
logging.error('Error occurred')
logging.critical('Critical error -- shutting down')

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

WARNING:root:Warning:config file server.conf not found
ERROR:root:Error occurred
CRITICAL:root:Critical error -- shutting down

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

Обратите внимание на использование в вызове warning() операторов форматирования строк; все функции регистрации сообщений принимают аргументы (msg, arg1, arg2, ...) и регистрируют строку, полученную из msg % (arg1, arg2, ...).

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

def f():
    try:    1/0
    except: logging.exception('Problem recorded')

f()

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

ERROR:root:Problem recorded
Traceback (most recent call last):
  File "t.py", line 6, in f
    1/0
ZeroDivisionError: integer division or modulo by zero

Чуть более продвинутые программы будут использовать логгер, отличный от корневого логгера. Функция getLogger(name) используется для получения определенного журнала и его создания, если он ещё не существует. getLogger(None) возвращает корневой логгер.

log = logging.getLogger('server')
 ...
log.info('Listening on port %i', port)
 ...
log.critical('Disk full')
 ...

Записи журнала обычно распространяются вверх по иерархии, поэтому сообщение, записанное в server.auth, также видят server и root, но Logger может предотвратить это, установив для атрибута propagate значение False.

Пакет logging предоставляет дополнительные классы, которые можно настраивать. Когда экземпляру Logger приказано зарегистрировать сообщение, он создаёт экземпляр LogRecord, который отправляется любому количеству различных экземпляров Handler. Логгеры и обработчики также могут иметь прикрепленный список фильтров, и каждый фильтр может привести к игнорированию LogRecord или может изменить запись перед её передачей. Когда они наконец выводятся, экземпляры LogRecord преобразуются в текст классом Formatter. Все данные классы можно заменить вашими специально написанными классами.

Со всеми этими функциями пакет logging должен обеспечивать достаточную гибкость даже для самых сложных приложений. Это лишь неполный обзор его функций, поэтому все подробности см. в справочной документации пакета. Чтение PEP 282 также будет полезно.

См.также

PEP 282 — Система регистрации
Авторы Винай Саджип и Трент Мик; реализован Винаем Саджипом.

PEP 285: логический тип

Булев тип был добавлен в Python 2.3. В модуль __builtin__ были добавлены две новые константы: True и False. (Константы True и False были добавлены к встроенным модулям в Python 2.2.1, но версии 2.2.1 просто устанавливаются в целые значения 1 и 0 и не являются другим типом.)

Объект типа для этого нового типа называется bool; конструктор для него принимает любое значение Python и преобразует его в True или False.

>>> bool(1)
True
>>> bool(0)
False
>>> bool([])
False
>>> bool( (1,) )
True

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

>>> obj = []
>>> hasattr(obj, 'append')
True
>>> isinstance(obj, list)
True
>>> isinstance(obj, tuple)
False

Логические значения Python были добавлены с основной целью сделать код более понятным. Например, если вы читаете функцию и встречаете оператор return 1, вы можете задаться вопросом, представляет ли 1 логическое значение истинности, индекс или коэффициент, который умножает какую-то другую величину. Однако, если оператор return True, смысл возвращаемого значения совершенно ясен.

Булевы значения Python были добавлены не для строгой проверки типов. Очень строгий язык, такой как Pascal, также не позволит вам выполнять арифметические операции с логическими значениями и потребует, чтобы выражение в операторе if всегда вычислялось как логический результат. Python не является таким строгим и никогда не будет таким, как прямо говорит PEP 285. Это означает, что вы по-прежнему можете использовать любое выражение в операторе if, даже такое, результатом которого является список, кортеж или какой-либо случайный объект. Тип Boolean является подклассом класса int, поэтому арифметика с использованием логического значения все ещё работает.

>>> True + 1
2
>>> False + 1
1
>>> False * 75
0
>>> True * 75
75

Подводя итог True и False в одном предложении: это альтернативные способы написания целых чисел 1 и 0, с той лишь разницей, что str() и repr() возвращают строки 'True' и 'False' вместо '1' и '0'.

См.также

PEP 285 — Добавление типа bool
Написано и реализовано GvR.

PEP 293: обратные вызовы при обработке ошибок кодека

При кодировании строки Юникод в строку байтов могут встречаться некодируемые символы. До сих пор Python разрешал указывать обработку ошибок как «строгую» (вызов UnicodeError), «игнорировать» (пропускать символ) или «заменять» (используя вопросительный знак в выходной строке), где «строгая» является поведение по умолчанию. Может оказаться желательным указать альтернативную обработку таких ошибок, например вставку ссылки на символ XML или ссылки на объект HTML в преобразованную строку.

У Python теперь есть гибкая структура для добавления различных стратегий обработки. Новые обработчики ошибок можно добавить с помощью codecs.register_error(), а затем кодеки могут получить доступ к обработчику ошибок с помощью codecs.lookup_error(). Эквивалентный C API был добавлен для кодеков, написанных на C. Обработчик ошибок получает необходимую информацию о состоянии, такую как преобразуемая строка, позиция в строке, где была обнаружена ошибка, и целевая кодировка. Затем обработчик может либо вызвать исключение, либо возвращает строку замены.

С помощью этой платформы были реализованы два дополнительных обработчика ошибок: «backslashreplace» использует кавычки Python с обратной косой чертой для представления некодируемых символов, а «xmlcharrefreplace» создаёт ссылки на символы XML.

См.также

PEP 293 — обратные вызовы при обработке ошибок кодека
Написано и реализовано Вальтером Дёрвальдом.

PEP 301: Указатель пакетов и метаданные для Distutils

Поддержка долгожданного каталога Python впервые появилась в версии 2.3.

Сердцем каталога является новая команда Distutils register. Запуск python setup.py register соберет метаданные, определяющие пакет, такие как его имя, версия, сопровождающий, описание и т. д., и отправит их на центральный сервер каталогов. Полученный каталог доступен по адресу.

Чтобы сделать каталог более полезным, в функцию Distutils setup() был добавлен новый необязательный ключевой аргумент classifiers. Список строк в стиле Trove может быть предоставлен для помощи в классификации программного обеспечения.

Вот пример setup.py с классификаторами, написанными для совместимости со старыми версиями Distutils:

from distutils import core
kw = {'name': "Quixote",
      'version': "0.5.1",
      'description': "A highly Pythonic Web application framework",
      # ...
      }

if (hasattr(core, 'setup_keywords') and
    'classifiers' in core.setup_keywords):
    kw['classifiers'] = \
        ['Topic :: Internet :: WWW/HTTP :: Dynamic Content',
         'Environment :: No Input/Output (Daemon)',
         'Intended Audience :: Developers'],

core.setup(**kw)

Полный список классификаторов можно получить, запустив python setup.py register --list-classifiers.

См.также

PEP 301 — индекс пакетов и метаданные для Distutils
Написано и реализовано Ричардом Джонсом.

PEP 302: Новые хуки импорта

Несмотря на то, что с тех пор, как модуль ihooks был представлен в Python 1.3, можно было писать собственные обработчики импорта, никто никогда не был им доволен, потому что написание новых обработчиков импорта сложно и запутанно. Были предложены различные альтернативы, такие как модули imputil и iu, но ни один из них так и не получил широкого признания, и ни один из них нельзя было легко использовать из кода C.

module: PEP 302 заимствует идеи у своих предшественников, особенно у модуля iu Гордона Макмиллана. В sys добавлены три новых элемента:

  • sys.path_hooks — список вызываемых объектов; чаще всего это будут классы. Каждый вызываемый объект принимает строку, содержащую путь, и либо возвращает объект импортера, который будет обрабатывать импорт из этого пути, либо вызывает исключение ImportError, если он не может обработать данный путь.
  • sys.path_importer_cache кэширует объекты импортера для каждого пути, поэтому sys.path_hooks нужно будет пройти только один раз для каждого пути.
  • sys.meta_path — это список объектов импортёра, которые будут пройдены перед проверкой sys.path. Данный список изначально пуст, но пользовательский код может добавлять в него объекты. Дополнительные встроенные и закрепленные модули могут быть импортированы объектом, добавленным в данный список.

Объекты Importer должны иметь один метод find_module(fullname, path=None). fullname будет именем модуля или пакета, например. string или distutils.core. find_module() должен возвращать объект-загрузчик с единственным методом load_module(fullname), который создаёт и возвращает соответствующий объект модуля.

Таким образом, псевдокод для новой логики импорта Python выглядит примерно так (немного упрощенно; полные подробности см. в PEP 302):

for mp in sys.meta_path:
    loader = mp(fullname)
    if loader is not None:
        <module> = loader.load_module(fullname)

for path in sys.path:
    for hook in sys.path_hooks:
        try:
            importer = hook(path)
        except ImportError:
            # ImportError, поэтому попробовать другие хуки пути
            pass
        else:
            loader = importer.find_module(fullname)
            <module> = loader.load_module(fullname)

# Не найден!
raise ImportError

См.также

PEP 302 — Новые импортные хуки
Авторы сценария Джаст ван Россум и Пол Мур. Реализован Джастом ван Россумом.

PEP 305: файлы, разделённые запятыми

Файлы с разделителями-запятыми — это формат, часто используемый для экспорта данных из баз данных и электронных таблиц. Python 2.3 добавляет парсер для файлов, разделенных запятыми.

Формат с разделителями-запятыми на первый взгляд обманчиво прост:

Costs,150,200,3.95

Прочитать строку и вызвать line.split(','): что может быть проще? Но добавить строковые данные, которые могут содержать запятые, и все станет сложнее:

"Costs",150,200,3.95,"Includes taxes, shipping, and sundry items"

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

import csv

input = open('datafile', 'rb')
reader = csv.reader(input)
for line in reader:
    print line

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

Можно определить и зарегистрировать различные диалекты файлов, разделенных запятыми; в настоящее время существует два диалекта, оба используются Microsoft Excel. Отдельный класс csv.writer будет генерировать файлы, разделенные запятыми, из последовательности кортежей или списков, заключая в кавычки строки, содержащие разделитель.

См.также

PEP 305 — API файлов CSV
Написано и реализовано Кевином Алтисом, Дэйвом Коулом, Эндрю Макнамарой, Скипом Монтанаро, Клифф Уэллс.

PEP 307: улучшения pickle

Модули pickle и cPickle привлекли некоторое внимание в ходе цикла разработки версии 2.3. В версии 2.2 классы нового стиля можно было без труда запиклить, но они не были запиклены очень компактно; PEP 307 цитирует тривиальный пример, когда класс нового стиля приводит к пиклинг строке в три раза длиннее, чем для классического класса.

Решение состояло в том, чтобы изобрести новый pickle протокол. Функция pickle.dumps() уже давно поддерживает текстовый или двоичный флаг. В версии 2.3 данный флаг изменён с логического на целое число: 0 — это старый текстовый формат pickle, 1 — старый двоичный формат, а теперь 2 — новый формат, специфичный для версии 2.3. Новая константа pickle.HIGHEST_PROTOCOL может использоваться для выбора самого модного из доступных протоколов.

Распаковка больше не считается безопасной операцией. pickle в версии 2.2 предоставлял ловушки для попыток предотвратить распаковку небезопасных классов (в частности, атрибут __safe_for_unpickling__), но ни один из данных кодов никогда не подвергался аудиту, и поэтому весь он был удален в версии 2.3. Вы не должны распаковывать ненадежные данные ни в одной версии Python.

Чтобы уменьшить накладные расходы на пиклинг для классов нового стиля, был добавлен новый интерфейс для настройки пиклинга с использованием трех специальных методов: __getstate__(), __setstate__() и __getnewargs__(). Консультируйтесь с PEP 307 для полной семантики данных методов.

В качестве способа ещё большего сжатия пикл теперь можно использовать целые коды вместо длинных строк для идентификации классов пикл. Python Software Foundation будет поддерживать список стандартизированных кодов; есть также ряд кодов для частного использования. На данный момент коды не указаны.

См.также

PEP 307 — Расширения для pickle протокола
Написано и реализовано Гвидо ван Россумом и Тимом Питерсом.

Расширенные срезы

Начиная с Python 1.4, синтаксис нарезки поддерживает необязательный третий аргумент — шаг. Например, это все допустимый синтаксис Python: L[1:10:2], L[:-1:1], L[::-1]. Это было добавлено в Python по просьбе разработчиков Numerical Python, в котором широко используется третий аргумент. Однако встроенные в Python типы списков, кортежей и строковых последовательностей никогда не поддерживали эту функцию, и если вы попробовали её, вы получить ошибку TypeError. Майкл Хадсон внёс патч, исправляющий данный недостаток.

Например, теперь вы можете легко извлекать элементы списка с чётными индексами:

>>> L = range(10)
>>> L[::2]
[0, 2, 4, 6, 8]

Отрицательные значения также работают для создания копии того же списка в обратном порядке:

>>> L[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

Это также работает для кортежей, массивов и строк:

>>> s='abcd'
>>> s[::2]
'ac'
>>> s[::-1]
'dcba'

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

>>> a = range(3)
>>> a
[0, 1, 2]
>>> a[1:3] = [4, 5, 6]
>>> a
[0, 4, 5, 6]

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

>>> a = range(4)
>>> a
[0, 1, 2, 3]
>>> a[::2]
[0, 2]
>>> a[::2] = [0, -1]
>>> a
[0, 1, -1, 3]
>>> a[::2] = [0,1,2]
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ValueError: attempt to assign sequence of size 3 to extended slice of size 2

Удаление более простое:

>>> a = range(4)
>>> a
[0, 1, 2, 3]
>>> a[::2]
[0, 2]
>>> del a[::2]
>>> a
[1, 3]

Также теперь можно передавать объекты среза в методы __getitem__() встроенных последовательностей:

>>> range(10).__getitem__(slice(0, 5, 2))
[0, 2, 4]

Или используйте объекты среза непосредственно в нижних индексах:

>>> range(10)[slice(0, 5, 2)]
[0, 2, 4]

Чтобы упростить реализацию последовательностей, поддерживающих расширенные срезы, у объектов срезов теперь есть учитывающий длину последовательности метод indices(length), возвращающий кортеж (start, stop, step), который можно передать непосредственно в range(). indices() обрабатывает пропущенные и выходящие за пределы индексы способом, совместимым с обычными срезами (и за этой безобидной фразой скрывается множество запутанных деталей!). Метод предназначен для использования таким образом:

class FakeSeq:
    ...
    def calc_item(self, i):
        ...
    def __getitem__(self, item):
        if isinstance(item, slice):
            indices = item.indices(len(self))
            return FakeSeq([self.calc_item(i) for i in range(*indices)])
        else:
            return self.calc_item(i)

Из этого примера также видно, что встроенный объект slice теперь является типом объекта для типа среза и больше не является функцией. Это согласуется с Python 2.2, где int, str и т. д. подверглись такому же изменению.

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

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

  • Оператор yield теперь всегда является ключевым словом, как приведено в разделе PEP 255: Простые генераторы этого документа.

  • Добавлена новая встроенная функция enumerate(), как приведено в разделе PEP 279: enumerate() этого документа.

  • Две новые константы, True и False, были добавлены вместе со встроенным типом bool, как приведено в разделе PEP 285: логический тип этого документа.

  • Конструктор типа int() теперь будет возвращать длинное целое число вместо того, чтобы вызвать OverflowError, когда строка или число с плавающей запятой слишком велики, чтобы поместиться в целое число. Это может привести к парадоксальному результату, что isinstance(int(expression), int) ложно, но вряд ли это вызовет проблемы на практике.

  • Встроенные типы теперь поддерживают расширенный синтаксис срезов, как приведено в разделе Расширенные срезы этого документа.

  • Новая встроенная функция sum(iterable, start=0) складывает числовые элементы в итерируемом объекте и возвращает их сумму. sum() принимает только числа, а это означает, что вы не можете использовать его для объединения нескольких строк. (Предоставлено Алексом Мартелли.)

  • list.insert(pos, value) раньше вставлял value в начало списка, когда pos был отрицательным. Теперь поведение было изменено, чтобы соответствовать индексации фрагментов, поэтому, когда pos равно -1, значение будет вставлено перед последним элементом и т. д.

  • list.index(value), который ищет value в списке и возвращает его индекс, теперь принимает необязательные аргументы start и stop, чтобы ограничить поиск только частью списка.

  • У словарей есть новый метод pop(key[, *default*]), который возвращает значение, соответствующее key, и удаляет эту пару ключ/значение из словаря. Если запрошенный ключ отсутствует в словаре, возвращается default, если он указан, и KeyError, если он не указан.

    >>> d = {1:2}
    >>> d
    {1: 2}
    >>> d.pop(4)
    Traceback (most recent call last):
      File "stdin", line 1, in ?
    KeyError: 4
    >>> d.pop(1)
    2
    >>> d.pop(1)
    Traceback (most recent call last):
      File "stdin", line 1, in ?
    KeyError: 'pop(): dictionary is empty'
    >>> d
    {}
    >>>
    

    Существует также новый метод класса, dict.fromkeys(iterable, value), который создаёт словарь с ключами, взятыми из предоставленного итератора iterable, и всеми значениями, установленными в value, по умолчанию None.

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

    Кроме того, конструктор dict() теперь принимает аргументы ключевых слов, чтобы упростить создание небольших словарей:

    >>> dict(red=1, blue=2, green=3, black=4)
    {'blue': 2, 'black': 4, 'green': 3, 'red': 1}
    

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

  • Оператор assert больше не проверяет флаг __debug__, поэтому вы больше не можете отключать утверждения, назначая __debug__. Запуск Python с переключателем -O по-прежнему будет генерировать код, который не выполняет никаких утверждений.

  • Большинство типовых объектов теперь можно вызывать, поэтому их можно использовать для создания новых объектов, например, функции, классы и модули. (Это означает, что модуль new может быть объявлен устаревшим в будущей версии Python, поскольку теперь вы можете использовать объекты типа, доступные в модуле types.) Например, вы можете создать новый объект модуля с помощью следующего кода:

    >>> import types
    >>> m = types.ModuleType('abc','docstring')
    >>> m
    <module 'abc' (built-in)>
    >>> m.__doc__
    'docstring'
    
  • Было добавлено новое предупреждение PendingDeprecationWarning, указывающее на функции, которые находятся в процессе устаревания. По умолчанию не будет напечатано предупреждение. Чтобы проверить использование функций, которые в будущем станут устаревшими, указать -Walways::PendingDeprecationWarning:: в командной строке или используйте warnings.filterwarnings().

  • Начался процесс отказа от строковых исключений, как в raise "Error occurred". Подъем строки теперь вызовет PendingDeprecationWarning.

  • Использование None в качестве имени переменной теперь приведёт к предупреждению SyntaxWarning. В будущей версии Python None может, наконец, стать ключевым словом.

  • Метод файловых объектов xreadlines(), представленный в Python 2.1, больше не нужен, поскольку теперь файлы ведут себя как собственные итераторы. xreadlines() изначально был введен как более быстрый способ перебора всех строк в файле, но теперь вы можете просто написать for line in file_obj. Файловые объекты также имеют новый доступный только для чтения атрибут encoding, который указывает кодировку, используемую файлом; Строки Юникод, записанные в файл, будут автоматически преобразованы в байты с использованием заданной кодировки.

  • Порядок разрешения методов, используемый классами нового стиля, изменился, хотя вы заметите разницу, только если у вас действительно сложная иерархия наследования. Классические классы не затронуты этим изменением. Python 2.2 изначально использовал топологический вид предков класса, но теперь 2.3 использует алгоритм C3, как приведено в статье «Монотонная линеаризация суперкласса для Дилана». Чтобы понять мотивацию этого изменения, прочитайте статью Микеле Симионато «Python 2.3 Method Resolution Order» или прочитайте ветку на python-dev, начинающуюся с сообщения по адресу https://mail.python.org/pipermail/python-dev/2002-October/029035.html. . Самуэле Педрони первым указал на проблему, а также реализовал исправление, написав алгоритм C3.

  • Python запускает многопоточные программы, переключаясь между потоками после выполнения N байт-кодов. Значение по умолчанию для N было увеличено с 10 до 100 байт-кодов, что ускоряет работу однопоточных приложений за счет уменьшения накладных расходов на переключение. Некоторые многопоточные приложения могут страдать от более медленного времени отклика, но это легко исправить, установив ограничение на меньшее число с помощью sys.setcheckinterval(N). Предел можно получить с помощью новой функции sys.getcheckinterval().

  • Одно незначительное, но далеко идущее изменение заключается в том, что имена типов расширений, определенных модулями, включенными в Python, теперь содержат модуль и '.' перед именем типа. Например, в Python 2.2, если вы создали сокет и напечатали его __class__, вы получить такой вывод:

    >>> s = socket.socket()
    >>> s.__class__
    <type 'socket'>
    

    В 2.3 вы получите:

    >>> s.__class__
    <type '_socket.socket'>
    
  • Одна из отмеченных несовместимостей между классами старого и нового стиля была устранена: теперь вы можете назначать атрибуты __name__ и __bases__ классов нового стиля. Существуют некоторые ограничения на то, что может быть назначено __bases__, аналогично тем, которые относятся к назначению атрибута экземпляра __class__.

Изменения строки

  • Оператор in теперь работает по-другому для строк. Раньше при вычислении X in Y, где X и Y — строки, X мог быть только одним символом. Теперь это изменилось; X может быть строкой любой длины, а X in Y вернёт True, если X является подстрокой Y. Если X — пустая строка, результатом всегда будет True.

    >>> 'ab' in 'abcd'
    True
    >>> 'ad' in 'abcd'
    False
    >>> '' in 'abcd'
    True
    

    Обратите внимание, что это не говорит вам, где начинается подстрока; если вам нужна информация, используйте строковый метод find().

  • У строковых методов strip(), lstrip() и rstrip() теперь есть необязательный аргумент для указания удаляемых символов. По умолчанию по-прежнему удаляются все пробельные символы:

    >>> '   abc '.strip()
    'abc'
    >>> '><><abc<><><>'.strip('<>')
    'abc'
    >>> '><><abc<><><>\n'.strip('<>')
    'abc<><><>\n'
    >>> u'\u4000\u4001abc\u4000'.strip(u'\u4000')
    u'\u4001abc'
    >>>
    

    (Предложено Саймоном Бруннингом и реализовано Вальтером Дёрвальдом.)

  • Строковые методы startswith() и endswith() теперь принимают отрицательные числа для параметров start и end.

  • Ещё один новый строковый метод — zfill(), первоначально являвшийся функцией модуля string. zfill() дополняет числовую строку нулями слева до указанной ширины. Обратите внимание, что оператор % по-прежнему более гибкий и мощный, чем zfill().

    >>> '45'.zfill(4)
    '0045'
    >>> '12345'.zfill(4)
    '12345'
    >>> 'goofy'.zfill(6)
    '0goofy'
    

    (Предоставлено Вальтером Дёрвальдом.)

  • Добавлен новый объект типа basestring. И 8-битные строки, и строки Юникод наследуются от этого типа, поэтому isinstance(obj, basestring) вернёт True для любого типа строки. Это полностью абстрактный тип, поэтому вы не можете создавать экземпляры basestring.

  • Интернированные строки больше не бессмертны и теперь будут собираться обычным способом, если единственная ссылка на них находится во внутреннем словаре интернированных строк. (Реализован Орен Тирош.)

Оптимизации

  • Создание экземпляров класса нового стиля стало намного быстрее; теперь они быстрее, чем классические классы!
  • Метод объектов списка sort() был тщательно переписан Тимом Питерсом, и его реализация значительно быстрее.
  • Умножение больших длинных целых чисел теперь выполняется намного быстрее благодаря реализации алгоритма умножения Карацубы, который масштабируется лучше, чем O(n*n), требуемый для школьного алгоритма умножения. (Исходный патч Кристофера А. Крейга, значительно переработанный Тимом Питерсом.)
  • Код операции SET_LINENO больше не используется. Это может обеспечить небольшое увеличение скорости, в зависимости от особенностей вашего компилятора. Подробное объяснение см. в разделе Другие изменения и исправления. (Удалено Майклом Хадсоном.)
  • Объекты xrange() теперь имеют собственный итератор, что делает for i in xrange(n) немного быстрее, чем for i in range(n). (Патч от Раймонда Хеттингера.)
  • В различных горячих точках был сделан ряд небольших изменений для повышения производительности, например встраивание функции или удаление некоторого кода. (Реализовано в основном GvR, но многие люди внесли отдельные изменения.)

Конечным результатом оптимизации 2.3 является то, что Python 2.3 выполняет тест pystone примерно на 25% быстрее, чем Python 2.2.

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

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

  • Модуль array теперь поддерживает массивы символов Юникод с использованием символа формата 'u'. Массивы также теперь поддерживают использование оператора присваивания += для добавления содержимого другого массива и оператора присваивания *= для повторения массива. (Предоставлено Джейсоном Орендорффом.)

  • Модуль bsddb был заменен версией 4.1.6 пакета PyBSDDB, предоставляя более полный интерфейс для транзакционных функций библиотеки BerkeleyDB.

    Старая версия модуля переименована в bsddb185 и больше не собирается автоматически; вам придется отредактировать Modules/Setup, чтобы включить его. Обратите внимание, что новый пакет bsddb предназначен для совместимости со старым модулем, поэтому обязательно сообщайте об ошибках, если обнаружите какие-либо несовместимости. При обновлении до Python 2.3, если новый интерпретатор скомпилирован с новой версией базовой библиотеки BerkeleyDB, вам почти наверняка придется преобразовать файлы базы данных в новую версию. Вы можете сделать это довольно легко с помощью новых сценариев db2pickle.py и pickle2db.py, которые вы найдете в каталоге дистрибутива Tools/scripts. Если вы уже использовали пакет PyBSDDB и импортировали его как bsddb3, вам придется изменить операторы import, чтобы импортировать его как bsddb.

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

  • В новый модуль datetime добавлен множество стандартных типов даты/времени. Дополнительные сведения см. в следующем разделе.

  • Класс Distutils Extension теперь поддерживает дополнительный аргумент конструктора с именем depends для перечисления дополнительных исходных файлов, от которых зависит расширение. Это позволяет Distutils перекомпилировать модуль при изменении любого из файлов зависимостей. Например, если sampmodule.c включает файл заголовка sample.h, вы должны создать объект Extension следующим образом:

    ext = Extension("samp",
                    sources=["sampmodule.c"],
                    depends=["sample.h"])
    

    Изменение sample.h приведёт к перекомпиляции модуля. (Предоставлено Джереми Хилтоном.)

  • Другие незначительные изменения в Distutils: теперь он проверяет переменные среды CC, CFLAGS, CPP, LDFLAGS и CPPFLAGS, используя их для переопределения настроек в конфигурации Python (предоставлено Робертом Вебером).

  • Раньше модуль doctest выполнял поиск тестовых случаев только в строках документации общедоступных методов и функций, но теперь он также проверяет и частные. Функция DocTestSuite() создаёт объект unittest.TestSuite из набора тестов doctest.

  • Новая функция gc.get_referents(object) возвращает список всех объектов, на которые ссылается object.

  • Модуль getopt получил новую функцию gnu_getopt(), которая поддерживает те же аргументы, что и существующая функция getopt(), но использует режим сканирования в стиле GNU. Существующий getopt() прекращает обработку параметров, как только встречается аргумент, не являющийся параметром, но в режиме в стиле GNU обработка продолжается, что означает, что параметры и аргументы могут быть смешаны. Например:

    >>> getopt.getopt(['-f', 'filename', 'output', '-v'], 'f:v')
    ([('-f', 'filename')], ['output', '-v'])
    >>> getopt.gnu_getopt(['-f', 'filename', 'output', '-v'], 'f:v')
    ([('-f', 'filename'), ('-v', '')], ['output'])
    

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

  • Модули grp, pwd и resource теперь возвращают расширенные кортежи:

    >>> import grp
    >>> g = grp.getgrnam('amk')
    >>> g.gr_name, g.gr_gid
    ('amk', 500)
    
  • Модуль gzip теперь может обрабатывать файлы размером более 2 ГБ.

  • Новый модуль heapq содержит реализацию алгоритма очереди кучи. Куча — это подобная массиву структура данных, которая хранит элементы в частично отсортированном порядке, так что для каждого индекса k, heap[k] <= heap[2*k+1] и heap[k] <= heap[2*k+2]. Это позволяет быстро удалить наименьший элемент, а вставка нового элемента с сохранением свойства кучи — O(lg n). (См. https://xlinux.nist.gov/dads//HTML/priorityque.html для получения дополнительной информации о структуре данных очереди приоритетов.)

    Модуль heapq предоставляет функции heappush() и heappop() для добавления и удаления элементов при сохранении свойства кучи поверх некоторого другого изменяемого типа последовательности Python. Вот пример, в котором используется список Python:

    >>> import heapq
    >>> heap = []
    >>> for item in [3, 7, 5, 11, 1]:
    ...    heapq.heappush(heap, item)
    ...
    >>> heap
    [1, 3, 5, 11, 7]
    >>> heapq.heappop(heap)
    1
    >>> heapq.heappop(heap)
    3
    >>> heap
    [5, 7, 11]
    

    (Предоставлено Кевином О’Коннором.)

  • Интегрированная среда разработки IDLE была обновлена с использованием кода из проекта IDLEfork (http://idlefork.sourceforge.net). Наиболее примечательной особенностью является то, что разрабатываемый код теперь выполняется в подпроцессе, а это означает, что больше нет необходимости в ручных операциях reload(). Основной код IDLE был включён в стандартную библиотеку в виде пакета idlelib.

  • Модуль imaplib теперь поддерживает IMAP через SSL. (Предоставлено Пирсом Лаудером и Тино Ланге.)

  • itertools содержит ряд полезных функций для использования с итераторами, вдохновленных различными функциями, предоставляемыми языками ML и Haskell. Например, itertools.ifilter(predicate, iterator) возвращает все элементы итератора, для которых функция predicate() возвращает True, а itertools.repeat(obj, N) возвращает obj N раз. В модуле есть ряд других функций; подробности см. в справочной документации пакета. (Предоставлено Рэймондом Хеттингером.)

  • Две новые функции в модуле math, degrees(rads) и radians(degs), выполняют преобразование между радианами и градусами. Другие функции в модуле math, такие как math.sin() и math.cos(), всегда требовали ввода значений в радианах. Кроме того, в math.log() был добавлен необязательный аргумент base, чтобы упростить вычисление логарифмов для оснований, отличных от e и 10. (Предоставлено Рэймондом Хеттингером.)

  • Несколько новых функций POSIX (getpgid(), killpg(), lchown(), loadavg(), major(), makedev(), minor() и mknod()) были добавлены в модуль posix, лежащий в основе модуля os. (Предоставили Густаво Нимейер, Герт Янсен и Денис С. Откидач.)

  • В модуле os семейство функций *stat() теперь может сообщать доли секунды в отметке времени. Такие метки времени представлены в виде чисел с плавающей запятой, аналогично значению, возвращаемому time.time().

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

    >>> os.stat("/tmp").st_mtime
    1034791200
    >>> os.stat_float_times(True)
    >>> os.stat("/tmp").st_mtime
    1034791200.6335014
    

    В Python 2.4 по умолчанию будет всегда возвращаться число с плавающей запятой.

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

  • Модуль optparse содержит новый синтаксический анализатор аргументов командной строки, который может преобразовывать значения параметров в определённый тип Python и автоматически генерировать сообщение об использовании. Дополнительные сведения см. в следующем разделе.

  • Старый и никогда не документированный модуль linuxaudiodev устарел, и была добавлена новая версия с именем ossaudiodev. Модуль был переименован, потому что звуковые драйверы OSS можно использовать на платформах, отличных от Linux, а интерфейс также был приведен в порядок и обновлен различными способами. (Предоставлено Грегом Уордом и Николасом Фицрой-Дейлом.)

  • Новый модуль platform содержит ряд функций, определяющих различные свойства работающей платформы. Есть функции для получения архитектуры, типа процессора, версии ОС Windows и даже версии дистрибутива Linux. (Предоставлено Марк-Андре Лембург.)

  • Объекты парсера, предоставляемые модулем pyexpat, теперь могут дополнительно буферизовать символьные данные, что приводит к меньшему количеству вызовов обработчика символьных данных и, следовательно, к более высокой производительности. Установка для атрибута buffer_text объекта анализатора значения True активирует буферизацию.

  • В модуль random добавлена функция sample(population, k). population представляет собой последовательность или объект xrange, содержащий элементы совокупности, а sample() выбирает элементы k из совокупности без замены выбранных элементов. k может быть любым значением до len(population). Например:

    >>> days = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'St', 'Sn']
    >>> random.sample(days, 3)      # Выберать 3 элемента
    ['St', 'Sn', 'Th']
    >>> random.sample(days, 7)      # Выберать 7 элементов
    ['Tu', 'Th', 'Mo', 'We', 'St', 'Fr', 'Sn']
    >>> random.sample(days, 7)      # Выберать 7 снова
    ['We', 'Mo', 'Sn', 'Fr', 'Tu', 'St', 'Th']
    >>> random.sample(days, 8)      # Не могу выбрать восемь
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
      File "random.py", line 414, in sample
          raise ValueError, "sample larger than population"
    ValueError: sample larger than population
    >>> random.sample(xrange(1,10000,2), 10)   # Выберать десять нечетных номеров, под 10000
    [3407, 3805, 1505, 7023, 2401, 2267, 9733, 3151, 8083, 9195]
    

    Модуль random теперь использует новый алгоритм Mersenne Twister, реализованный на языке C. Он работает быстрее и лучше изучен, чем предыдущий алгоритм.

    (Все изменения внес Рэймонд Хеттингер.)

  • Модуль readline также получил ряд новых функций: get_history_item(), get_current_history_length() и redisplay().

  • Модули rexec и Bastion были объявлены мертвыми, и попытки импортировать их завершатся с ошибкой RuntimeError. Классы нового стиля предоставляют новые способы выхода из ограниченной среды выполнения, предоставляемой rexec, и никто не заинтересован в их исправлении или нет времени для этого. Если у вас есть приложения, использующие rexec, перепишите их, чтобы они использовали что-то другое.

    (Использование Python 2.2 или 2.1 не сделает ваши приложения более безопасными, потому что в данных версиях есть известные ошибки в модуле rexec. Повторюсь: если вы используете rexec, немедленно прекратить его использовать.)

  • Модуль rotor устарел, т. к. алгоритм, который он использует для шифрования, не считается безопасным. Если вам нужно шифрование, используйте один из нескольких модулей AES Python, которые доступны отдельно.

  • Модуль shutil получил функцию move(src, dest), которая рекурсивно перемещает файл или каталог в новое место.

  • Поддержка более продвинутой обработки сигналов POSIX была добавлена в signal, но затем снова удалена, поскольку оказалось невозможным обеспечить его надежную работу на разных платформах.

  • Модуль socket теперь поддерживает тайм-ауты. Вы можете вызвать метод settimeout(t) для объекта сокета, чтобы установить время ожидания t секунд. Последующие операции сокета, выполнение которых занимает больше t секунд, будут прерваны и вызовут исключение socket.timeout.

    Первоначальная реализация тайм-аута была разработана Тимом О’Мэлли. Майкл Гилфикс интегрировал его в модуль Python socket и подробно рассмотрел. После проверки кода, Гвидо ван Россумом переписал его части. (Это хороший пример процесса совместной разработки в действии.)

  • В Windows модуль socket теперь поставляется с поддержкой Secure Sockets Layer (SSL).

  • Значение макроса C PYTHON_API_VERSION теперь отображается на уровне Python как sys.api_version. Текущее исключение можно очистить, вызвав новую функцию sys.exc_clear().

  • Новый модуль tarfile позволяет читать и записывать в архивные файлы формата tar. (Предоставлено Ларсом Густебелем.)

  • Новый модуль textwrap содержит функции для переноса строк, содержащих абзацы текста. Функция wrap(text, width) принимает строку и возвращает список, содержащий текст, разбитый на строки не более выбранной ширины. Функция fill(text, width) возвращает одну строку, переформатированную так, чтобы она помещалась в строки не длиннее выбранной ширины. (Как вы можете догадаться, fill() построен поверх wrap(). Например:

    >>> import textwrap
    >>> paragraph = "Not a whit, we defy augury: ... more text ..."
    >>> textwrap.wrap(paragraph, 60)
    ["Not a whit, we defy augury: there's a special providence in",
     "the fall of a sparrow. If it be now, 'tis not to come; if it",
     ...]
    >>> print textwrap.fill(paragraph, 35)
    Not a whit, we defy augury: there's
    a special providence in the fall of
    a sparrow. If it be now, 'tis not
    to come; if it be not to come, it
    will be now; if it be not now, yet
    it will come: the readiness is all.
    >>>
    

    Модуль также содержит класс TextWrapper, который фактически реализует стратегию переноса текста. Как класс TextWrapper, так и функции wrap() и fill() поддерживают ряд дополнительных аргументов с ключевыми словами для тонкой настройки форматирования; обратитесь к документации модуля за подробностями. (Предоставлено Грегом Уордом.)

  • Модули thread и threading теперь имеют сопутствующие модули, dummy_thread и dummy_threading, которые обеспечивают реализацию интерфейса модуля thread без каких-либо действий для платформ, где потоки не поддерживаются. Намерение состоит в том, чтобы упростить модули с поддержкой потоков (т.е, которые не полагаются на потоки для запуска), поместив следующий код вверху:

    try:
        import threading as _threading
    except ImportError:
        import dummy_threading as _threading
    

    В этом примере в качестве имени модуля используется _threading, чтобы было ясно, что используемый модуль не обязательно является фактическим модулем threading. Код может вызывать функции и использовать классы в _threading независимо от того, поддерживаются ли потоки, избегая оператора if и делая код немного понятнее. Данный модуль не волшебным образом заставит многопоточный код работать без потоков; код, ожидающий возврата или выполнения какого-либо другого потока, просто зависнет навсегда.

  • Функция strptime() модуля time долгое время вызывала раздражение, поскольку она использует реализацию strptime() библиотеки C для платформы, а на разных платформах иногда происходят странные ошибки. Бретт Кэннон предоставил переносимую реализацию, написанную на чистом Python, которая должна вести себя одинаково на всех платформах.

  • Новый модуль timeit помогает измерять, сколько времени требуется для выполнения фрагментов кода Python. Файл timeit.py можно запустить непосредственно из командной строки, или класс модуля Timer можно импортировать и использовать напрямую. Вот короткий пример, который показывает, быстрее ли преобразовать 8-битную строку в Юникод, добавив к ней пустую строку Юникод или используя функцию unicode():

    import timeit
    
    timer1 = timeit.Timer('unicode("abc")')
    timer2 = timeit.Timer('"abc" + u""')
    
    # Провести три испытания
    print timer1.repeat(repeat=3, number=100000)
    print timer2.repeat(repeat=3, number=100000)
    
    # На моем ноутбуке это выводит:
    # [0.36831796169281006, 0.37441694736480713, 0.35304892063140869]
    # [0.17574405670166016, 0.18193507194519043, 0.17565798759460449]
    
  • Модуль Tix получил различные исправления ошибок и обновления для текущей версии пакета Tix.

  • Модуль Tkinter теперь работает с версией Tcl с поддержкой потоков. Потоковая модель Tcl требует, чтобы доступ к виджетам осуществлялся только из потока, в котором они созданы; доступ из другого потока может вызвать панику Tcl. Для определенных интерфейсов Tcl Tkinter теперь будет автоматически избегать этого при доступе к виджету из другого потока путём сортировки команды, передачи её в правильный поток и ожидания результатов. Другие интерфейсы не могут обрабатываться автоматически, но Tkinter теперь будет вызывать исключение при таком доступе, чтобы вы могли хотя бы узнать о проблеме. См. https://mail.python.org/pipermail/python- dev/2002-December/031107.html для более подробного объяснения этого изменения. (Реализовано Мартином фон Лёвисом)

  • Вызов методов Tcl через _tkinter больше не возвращает только строки. Вместо этого, если Tcl возвращает другие объекты, данные объекты преобразуются в их эквиваленты Python, если они существуют, или оборачиваются в объект _tkinter.Tcl_Obj, если эквивалентов Python не существует. Этим поведением можно управлять с помощью метода wantobjects() объектов tkapp.

    При использовании _tkinter через модуль Tkinter (как и большинство приложений Tkinter) данная функция всегда активирована. Это не должно вызывать проблем с совместимостью, поскольку Tkinter всегда будет преобразовывать строковые результаты в типы Python, где это возможно.

    Если обнаружены какие-либо несовместимости, старое поведение можно восстановить, установив для переменной wantobjects в модуле Tkinter значение ложь перед созданием первого объекта tkapp.

    import Tkinter
    Tkinter.wantobjects = 0
    

    О любой поломке, вызванной этим изменением, следует сообщать как об ошибке.

  • У модуля UserDict появился новый класс DictMixin, определяющий все методы словаря для классов, у которых уже есть минимальный интерфейс сопоставления. Это значительно упрощает написание классов, которые необходимо заменять словарями, например, классы в модуле shelve.

    Добавление примеси в качестве суперкласса обеспечивает полный интерфейс словаря всякий раз, когда класс определяет __getitem__(), __setitem__(), __delitem__() и keys(). Например:

    >>> import UserDict
    >>> class SeqDict(UserDict.DictMixin):
    ...     """Dictionary lookalike implemented with lists."""
    ...     def __init__(self):
    ...         self.keylist = []
    ...         self.valuelist = []
    ...     def __getitem__(self, key):
    ...         try:
    ...             i = self.keylist.index(key)
    ...         except ValueError:
    ...             raise KeyError
    ...         return self.valuelist[i]
    ...     def __setitem__(self, key, value):
    ...         try:
    ...             i = self.keylist.index(key)
    ...             self.valuelist[i] = value
    ...         except ValueError:
    ...             self.keylist.append(key)
    ...             self.valuelist.append(value)
    ...     def __delitem__(self, key):
    ...         try:
    ...             i = self.keylist.index(key)
    ...         except ValueError:
    ...             raise KeyError
    ...         self.keylist.pop(i)
    ...         self.valuelist.pop(i)
    ...     def keys(self):
    ...         return list(self.keylist)
    ...
    >>> s = SeqDict()
    >>> dir(s)      # Посмотрите, реализованы ли другие методы словаря
    ['__cmp__', '__contains__', '__delitem__', '__doc__', '__getitem__',
     '__init__', '__iter__', '__len__', '__module__', '__repr__',
     '__setitem__', 'clear', 'get', 'has_key', 'items', 'iteritems',
     'iterkeys', 'itervalues', 'keylist', 'keys', 'pop', 'popitem',
     'setdefault', 'update', 'valuelist', 'values']
    

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

  • Реализация DOM в xml.dom.minidom теперь может генерировать выходные данные XML в определенной кодировке, предоставляя необязательный аргумент кодировки для методов toxml() и toprettyxml() узлов DOM.

  • Модуль xmlrpclib теперь поддерживает расширение XML-RPC для обработки нулевых значений данных, например None Python. Значения Nil всегда поддерживаются при разупорядочении ответа XML-RPC. Чтобы сгенерировать запросы, содержащие None, необходимо указать истинное значение для параметра allow_none при создании экземпляра Marshaller.

  • Новый модуль DocXMLRPCServer позволяет писать самодокументирующиеся серверы XML-RPC. Запустить его в демонстрационном режиме (как программу), чтобы увидеть его в действии. Указание веб-браузеру на сервер RPC создаёт документацию в стиле pydoc; указание xmlrpclib на сервер позволяет вызывать фактические методы. (Предоставлено Брайаном Куинланом.)

  • Добавлена поддержка интернационализированных доменных имён (RFC 3454, 3490, 3491 и 3492). Кодировку «idna» можно использовать для преобразования между доменным именем Юникод и ASCII-совместимой кодировкой (ACE) этого имени.

    >{}>{}> u"www.Alliancefrançaise.nu".encode("idna")
    'www.xn--alliancefranaise-npb.nu'
    

    Модуль socket также был расширен для прозрачного преобразования имён хостов Юникод в версию ACE перед их передачей в библиотеку C. Модули, работающие с именами хостов (например, httplib и ftplib), также поддерживают имена хостов в формате Юникод; httplib также отправляет заголовки HTTP Host, используя версию доменного имени ACE. urllib поддерживает URL-адреса Юникод с именами хостов, отличными от ASCII, если часть URL-адреса path является только ASCII.

    Для реализации этого изменения были добавлены модуль stringprep, инструмент mkstringprep и кодировка punycode.

Тип даты/времени

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

Три основных типа: date, представляющие день, месяц и год; time, состоящий из часов, минут и секунд; и datetime, который содержит все атрибуты date и time. Существует также класс timedelta, представляющий различия между двумя моментами времени, а логика часовых поясов реализуется классами, унаследованными от абстрактного класса tzinfo.

Вы можете создавать экземпляры date и time, либо передавая ключевые аргументы соответствующему конструктору, например. datetime.date(year=1972, month=10, day=15) или с помощью одного из нескольких методов класса. Например, метод класса date.today() возвращает текущую локальную дату.

После создания все экземпляры классов даты/времени неизменяемы. Существует несколько методов создания форматированных строк из объектов:

>>> import datetime
>>> now = datetime.datetime.now()
>>> now.isoformat()
'2002-12-30T21:27:03.994956'
>>> now.ctime()  # Доступно только на дату, дату и время
'Mon Dec 30 21:27:03 2002'
>>> now.strftime('%Y %d %b')
'2002 30 Dec'

Метод replace() позволяет изменить одно или несколько полей экземпляра date или datetime, возвращая новый экземпляр:

>>> d = datetime.datetime.now()
>>> d
datetime.datetime(2002, 12, 30, 22, 15, 38, 827738)
>>> d.replace(year=2001, hour = 12)
datetime.datetime(2001, 12, 30, 12, 15, 38, 827738)
>>>

Экземпляры можно сравнивать, хешировать и преобразовывать в строки (результат такой же, как у isoformat()). Экземпляры date и datetime можно вычитать друг из друга и добавлять к экземплярам timedelta. Самая большая недостающая функция заключается в том, что стандартная библиотека не поддерживает парсинг строк и получение date или datetime.

Для получения дополнительной информации обратитесь к справочной документации модуля. (Предоставлено Тимом Питерсом.)

Модуль optparse

Модуль getopt обеспечивает простой разбор аргументов командной строки. Новый модуль optparse (первоначально называвшийся Optik) обеспечивает более сложный парсинг командной строки, соответствующий соглашениям Unix, автоматически создаёт выходные данные для --help и может выполнять различные действия для разных параметров.

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

import sys
from optparse import OptionParser

op = OptionParser()
op.add_option('-i', '--input',
              action='store', type='string', dest='input',
              help='set input filename')
op.add_option('-l', '--length',
              action='store', type='int', dest='length',
              help='set maximum length of output')

Затем парсинг командной строки выполняется путём вызова метода parse_args().

options, args = op.parse_args(sys.argv[1:])
print options
print args

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

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

$ ./python opt.py -i data arg1
<Values at 0x400cad4c: {'input': 'data', 'length': None}>
['arg1']
$ ./python opt.py --input=data --length=4
<Values at 0x400cad2c: {'input': 'data', 'length': 4}>
[]
$

Справочное сообщение генерируется автоматически:

$ ./python opt.py --help
usage: opt.py [options]

options:
  -h, --help            show this help message and exit
  -iINPUT, --input=INPUT
                        set input filename
  -lLENGTH, --length=LENGTH
                        set maximum length of output
$

См. документацию модуля для более подробной информации.

Optik был написан Грегом Уордом с предложениями читателей Getopt SIG.

Pymalloc: специализированный распределитель объектов

Pymalloc, специализированный распределитель объектов, написанный Владимиром Марангозовым, был добавлен в Python 2.1. Предполагается, что Pymalloc будет работать быстрее, чем система malloc(), и иметь меньшие накладные расходы памяти для шаблонов распределения, типичных для программ Python. Распределитель использует функцию C malloc() для получения больших пулов памяти, а затем выполняет меньшие запросы памяти из данных пулов.

В версиях 2.1 и 2.2 pymalloc был экспериментальной функцией и не был включён по умолчанию; вам нужно было явно включить его при компиляции Python, указав параметр --with-pymalloc для сценария configure. В версии 2.3 в pymalloc были внесены дополнительные улучшения, и теперь он включён по умолчанию; вам нужно будет указать --without-pymalloc, чтобы отключить его.

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

Есть одна особенно распространенная ошибка, которая вызывает проблемы. В Python C API есть ряд функций распределения памяти, которые ранее были просто псевдонимами для malloc() и free() библиотеки C, а это означает, что если вы случайно вызовете несовпадающие функции, ошибка не будет заметной. Когда распределитель объектов включён, данные функции больше не являются псевдонимами malloc() и free(), и вызов неправильной функции для освобождения памяти может привести к дампу ядра. Например, если память была выделена с помощью PyObject_Malloc(), её нужно освободить с помощью PyObject_Free(), а не free(). Несколько модулей, включенных в Python, не соответствовали этому, и их пришлось исправлять; несомненно, есть и другие сторонние модули, которые будут иметь ту же проблему.

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

  • Чтобы выделить и освободить незаметный фрагмент памяти, используйте семейство «необработанной памяти»: PyMem_Malloc(), PyMem_Realloc() и PyMem_Free().
  • Семейство «объектная память» представляет собой интерфейс к описанному выше средству pymalloc и ориентировано на большое количество «маленьких» распределений: PyObject_Malloc(), PyObject_Realloc() и PyObject_Free().
  • Чтобы выделить и освободить объекты Python, используйте семейство «объектов» PyObject_New(), PyObject_NewVar() и PyObject_Del().

Благодаря большой работе Тима Питерса, pymalloc в версии 2.3 также предоставляет функции отладки для обнаружения перезаписей памяти и двойных освобождений как в модулях расширения, так и в самом интерпретаторе. Чтобы включить эту поддержку, скомпилируйте отладочную версию интерпретатора Python, запустив configure с --with-pydebug.

Чтобы помочь авторам расширений, вместе с исходным кодом Python 2.3 распространяется заголовочный файл Misc/pymemcompat.h, который позволяет расширениям Python использовать интерфейсы 2.3 для выделения памяти при компиляции с любой версией Python, начиная с 1.5.2. Вы должны скопировать файл из исходного дистрибутива Python и связать его с исходным кодом вашего расширения.

См.также

https://hg.python.org/cpython/file/default/Objects/obmalloc.c
Полную информацию о реализации pymalloc см. в комментариях по адресу верхняя часть файла Objects/obmalloc.c в исходном коде Python. Приведённая выше ссылка указывает на файл в браузере python.org SVN.

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

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

  • Реализация обнаружения циклов, используемая сборщиком мусора, оказалась стабильной, поэтому теперь она стала обязательной. Вы больше не можете компилировать Python без него, а переключатель --with-cycle-gc на configure был удалён.
  • Теперь Python можно дополнительно собрать как общую библиотеку (libpython2.3.so), указав --enable-shared при запуске скрипта Python configure. (Предоставлено Ондреем Палковски.)
  • Макросы DL_EXPORT и DL_IMPORT устарели. Функции инициализации для модулей расширения Python теперь должны быть объявлены с использованием нового макроса PyMODINIT_FUNC, в то время как ядро Python обычно использует макросы PyAPI_FUNC и PyAPI_DATA.
  • Интерпретатор можно скомпилировать без каких-либо строк документации для встроенных функций и модулей, указав --without-doc-strings в сценарии configure. Это делает исполняемый файл Python примерно на 10% меньше, но также означает, что вы не сможете получить помощь по встроенным модулям Python. (Предоставлено Густаво Нимейером.)
  • Макрос PyArg_NoArgs() теперь устарел, и код, который его использует, должен быть изменён. Для Python 2.2 и более поздних версий в таблице определения методов может быть указан флаг METH_NOARGS, сигнализирующий об отсутствии аргументов, после чего проверка аргументов может быть удалена. Если важна совместимость с версиями Python до версии 2.2, код может использовать PyArg_ParseTuple(args, "") вместо этого, но это будет медленнее, чем использование METH_NOARGS.
  • PyArg_ParseTuple() принимает символы нового формата для различных размеров целых чисел без знака: B для unsigned char, H для unsigned short int, I для unsigned int и K для unsigned long long.
  • Новая функция PyObject_DelItemString(mapping, char *key) была добавлена в качестве сокращения для PyObject_DelItem(mapping, PyString_New(key)).
  • Файловые объекты теперь иначе управляют своим внутренним строковым буфером, экспоненциально увеличивая его при необходимости. Это приводит к значительному ускорению тестов производительности в Lib/test/test_bufio.py (с 57 секунд до 1,7 секунд, согласно одному измерению).
  • Теперь можно определить класс и статические методы для типа расширения C, установив флаги METH_CLASS или METH_STATIC в структуре метода PyMethodDef.
  • Python теперь включает копию исходного кода парсера Expat XML, устраняя любую зависимость от версии системы или локальной установки Expat.
  • Если вы динамически размещаете объекты типа в своём расширении, вы должны знать об изменении правил, касающихся атрибутов __module__ и __name__. Таким образом, вы должны убедиться, что словарь типа содержит ключ '__module__'; создание имени модуля частью имени типа, ведущей к последней точке, больше не будет иметь желаемого эффекта. Дополнительные сведения см. в справочной документации по API или в источнике.

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

Поддержка переноса на IBM OS/2 с использованием среды выполнения EMX была объединена с основным деревом исходного кода Python. EMX — это уровень эмуляции POSIX поверх системных API OS/2. Порт Python для EMX пытается поддерживать все POSIX-подобные возможности, предоставляемые средой выполнения EMX, и в основном это удается; fork() и fcntl() ограничены ограничениями нижележащего уровня эмуляции. Стандартный порт OS/2, который использует компилятор IBM Visual Age, также получил поддержку семантики импорта с учётом регистра как часть интеграции порта EMX в CVS. (Предоставлено Эндрю Макинтайром.)

В MacOS большинство модулей инструментов были слабо связаны для улучшения обратной совместимости. Это означает, что модули больше не будут терпеть неудачу при загрузке, если в текущей версии ОС отсутствует хотя бы одна подпрограмма. Вместо этого вызов отсутствующей подпрограммы вызовет исключение. (Предоставлено Джеком Янсеном.)

Файлы спецификаций RPM, находящиеся в каталоге Misc/RPM/ исходного дистрибутива Python, были обновлены для версии 2.3. (Предоставлено Шоном Рейфшнайдером)

Другие новые платформы, теперь поддерживаемые Python, включают AtheOS (http://www.atheos.cx/), GNU/Hurd и OpenVMS.

Другие изменения и исправления

Как обычно, по всему дереву исходников было разбросано множество других улучшений и исправлений. Поиск в журналах изменений CVS показал, что между Python 2.2 и 2.3 было применено 523 исправления и исправлено 514 ошибок. Обе цифры, вероятно, занижены.

Некоторые из наиболее заметных изменений:

  • Если установлена переменная среды PYTHONINSPECT, интерпретатор Python выведет интерактивную подсказку после запуска программы Python, как если бы Python был запущен с параметром -i. Переменная среды может быть установлена перед запуском интерпретатора Python или может быть установлена программой Python как часть её выполнения.

  • Сценарий regrtest.py теперь позволяет разрешить «все ресурсы, кроме foo». Имя ресурса, переданное параметру -u, теперь может иметь префикс дефиса ('-'), что означает «удалить данный ресурс». Например, параметр «-uall,-bsddb» может использоваться для разрешения использования всех ресурсов, кроме bsddb.

  • Инструменты, используемые для создания документации, теперь работают как в Cygwin, так и в Unix.

  • Код операции SET_LINENO был удален. В давние времена данный код операции был необходим для создания номеров строк в обратных трассировках и поддержки функций трассировки (например, для pdb). Начиная с Python 1.5, номера строк в трассировках вычисляются с использованием другого механизма, который работает с «python -O». Для Python 2.3 Майкл Хадсон реализовал аналогичную схему, чтобы определить, когда вызывать функцию трассировки, полностью устранив необходимость в SET_LINENO.

    Было бы трудно обнаружить какое-либо результирующее отличие от кода Python, за исключением небольшого ускорения, когда Python запускается без -O.

    Расширения C, которые обращаются к полю f_lineno объектов фрейма, должны вместо этого вызывать PyCode_Addr2Line(f->f_code, f->f_lasti). Это предоставит дополнительный эффект, заставив код работать так, как хотелось бы, в «python -O» в более ранних версиях Python.

    Отличная новая функция заключается в том, что функции трассировки теперь могут назначать атрибут f_lineno объектов фрейма, изменяя строку, которая будет выполняться следующей. В отладчик pdb добавлена команда jump, использующая эту новую функцию. (Реализовано Ричи Хиндлом.)

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

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

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

  • Для строк X и Y, X in Y теперь работает, если X содержит более одного символа.

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

  • Если у вас есть строки Юникод, содержащие 8-битные символы, вы должны объявить кодировку файла (UTF-8, Latin-1 или любую другую), добавив комментарий в начало файла. Дополнительную информацию см. в разделе PEP 263: Кодировки исходного кода.

  • Вызов методов Tcl через _tkinter больше не возвращает только строки. Вместо этого, если Tcl возвращает другие объекты, данные объекты преобразуются в их эквиваленты Python, если они существуют, или оборачиваются в объект _tkinter.Tcl_Obj, если эквивалентов Python не существует.

  • Большие восьмеричные и шестнадцатеричные литералы, такие как 0xffffffff, теперь вызывают FutureWarning. В настоящее время они хранятся как 32-битные числа и дают отрицательное значение, но в Python 2.4 они станут положительными длинными целыми числами.

    Есть несколько способов исправить это предупреждение. Если вам действительно нужно положительное число, просто добавить L в конец литерала. Если вы пытаетесь получить 32-битное целое число с установленными младшими битами и ранее использовали выражение, такое как ~(1 << 31), вероятно, будет проще начать со всех установленных битов и очистить желаемые старшие биты. Например, чтобы очистить только верхний бит (бит 31), вы можете написать 0xffffffffL &~(1L<<31).

  • Вы больше не можете отключить утверждения, назначив __debug__.

  • Функция Distutils setup() получила различные новые ключевые аргументы, такие как depends. Старые версии Distutils прервут работу, если будут переданы неизвестные ключевые слова. Решение состоит в том, чтобы проверить наличие новой функции get_distutil_options() в вашем setup.py и использовать новые ключевые слова только с той версией Distutils, которая их поддерживает:

    from distutils import core
    
    kw = {'sources': 'foo.c', ...}
    if hasattr(core, 'get_distutil_options'):
        kw['depends'] = ['foo.h']
    ext = Extension(**kw)
    
  • Использование None в качестве имени переменной теперь приведёт к предупреждению SyntaxWarning.

  • Имена типов расширений, определённые модулями, включенными в Python, теперь содержат модуль и '.' перед именем типа.

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

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