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

Автор:

А.М. Кючлинг

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

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

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

В этой статье не делается попытка дать полное описание новых возможностей, а вместо этого приводится удобный обзор. За подробной информацией следует обращаться к документации по Python 2.3, такой как Python Library Reference и Python Reference Manual. Если вы хотите понять полную реализацию и обоснование дизайна, обратитесь к 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(); в альтернативной нотации используются побитовые операторы & и |. У изменяемых множеств также есть in-place версии этих методов, 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                  # Alternative notation
Set([1, 2, 3, 4, 5, 6])
>>> S1.intersection(S2)
Set([])
>>> S1 & S2                  # Alternative notation
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 написан Грегом В. Уилсоном. Реализовано Грегом В. Уилсоном, Алексом Мартелли и GvR.

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

# A recursive generator that generates Tree leaves in in-order.
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-Queens (размещение $N$ ферзей на шахматной доске $NxN$ так, чтобы ни один ферзь не угрожал другому) и Knight’s Tour (маршрут, по которому конь попадает на каждую клетку шахматной доски $NxN$, не посещая ни одну клетку дважды).

Идея генераторов пришла из других языков программирования, особенно из Icon (https://www2.cs.arizona.edu/icon/), где идея генераторов занимает центральное место. В Icon каждое выражение и вызов функции ведут себя как генератор. Один пример из «Обзора языка программирования Icon» на https://www2.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-архивов

Написана Джеймсом К. Альстромом, который также предоставил реализацию. Python 2.3 следует спецификации в PEP 273, но использует реализацию, написанную Джастом ван Россумом, которая использует крючки импорта, описанные в PEP 302. Описание новых крючков импорта см. в разделе PEP 302: Новые крючки импорта.

PEP 277: Поддержка имен файлов Unicode в Windows NT

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

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

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

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

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

См.также

PEP 277 - Поддержка имен файлов в кодировке Unicode для Windows NT

Автор Нил Ходжсон; реализовано Нилом Ходжсоном, Мартином фон Лёвисом и Марком Хэммондом.

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

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

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

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

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

См.также

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]
    # ... compute some result based on item ...
    L[i] = result

Это можно переписать с помощью enumerate() так:

for i, item in enumerate(L):
    # ... compute some result based on item ...
    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 содержит несколько удобных функций, которые всегда используют корневой log:

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

>>> 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: Обратные вызовы для обработки ошибок кодеков

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

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

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

См.также

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

Автор и исполнитель Вальтер Дёрвальд.

PEP 301: Индекс пакетов и метаданные для Distutils

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

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

Чтобы сделать каталог немного более полезным, в функцию 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: Новые крючки импорта

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

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

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

  • sys.path_importer_cache кэширует объекты импортера для каждого пути, поэтому sys.path_hooks нужно будет обойти только один раз для каждого пути.

  • sys.meta_path - это список объектов-импортеров, которые будут пройдены перед проверкой sys.path. Изначально этот список пуст, но пользовательский код может добавлять в него объекты. Дополнительные встроенные и замороженные модули могут быть импортированы объектом, добавленным в этот список.

Объекты импортера должны иметь единственный метод, 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, so try the other path hooks
            pass
        else:
            loader = importer.find_module(fullname)
            <module> = loader.load_module(fullname)

# Not found!
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 может быть использована для выбора самого удобного протокола.

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

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

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

См.также

PEP 307 - Расширения для протокола pickle

Авторы и исполнители: Гвидо ван Россум и Тим Питерс.

Расширенные ломтики

Начиная с Python 1.4, синтаксис нарезки поддерживает необязательный третий аргумент «step» или «stride». Например, все эти аргументы являются законными в синтаксисе 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]

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

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

Чтобы упростить реализацию последовательностей, поддерживающих расширенную нарезку, объекты slice теперь имеют метод 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 теперь является объектом типа для типа 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) складывает числовые элементы в объекте iterable и возвращает их сумму. sum() принимает только числа, то есть вы не сможете использовать ее для конкатенации строк. (Внесено Алексом Мартелли.)

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

  • list.index(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, доступный только для чтения, который указывает кодировку, используемую файлом; строки Unicode, записанные в файл, будут автоматически преобразованы в байты с использованием указанной кодировки.

  • Порядок разрешения методов, используемый классами нового стиля, изменился, но вы заметите разницу, только если у вас очень сложная иерархия наследования. Классические классы это изменение не затронуло. В Python 2.2 изначально использовалась топологическая сортировка предков класса, но в 2.3 теперь используется алгоритм C3, описанный в статье «A Monotonic Superclass Linearization for Dylan». Чтобы понять мотивацию этого изменения, прочтите статью Микеле Симионато Порядок разрешения методов в Python 2.3 или прочитайте тему на 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-битные строки, так и строки Unicode, поэтому isinstance(obj, basestring) вернет True для любого типа строк. Это полностью абстрактный тип, поэтому вы не можете создавать экземпляры basestring.

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

Оптимизации

  • Создание экземпляров классов нового стиля стало намного быстрее: теперь они создаются быстрее, чем классические классы!

  • Метод sort() для списочных объектов был существенно переписан Тимом Питерсом, и его реализация стала значительно быстрее.

  • Умножение больших длинных целых чисел теперь выполняется намного быстрее благодаря реализации умножения Карацубы - алгоритма, который масштабируется лучше, чем O(n2), требуемый для школьного алгоритма умножения. (Оригинальный патч Кристофера А. Крейга, значительно переработанный Тимом Питерсом).

  • Опкод SET_LINENO теперь отсутствует. Это может дать небольшой прирост скорости, в зависимости от особенностей вашего компилятора. Более подробное объяснение см. в разделе Другие изменения и исправления. (Удалено Майклом Хадсоном).

  • Объекты xrange() теперь имеют собственный итератор, что делает for i in xrange(n) немного быстрее, чем for i in range(n). (Исправление от Raymond Hettinger.)

  • В различных местах были сделаны небольшие перестановки для повышения производительности, например, вставка функций или удаление некоторого кода. (Реализовано в основном 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(log 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 (https://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)      # Choose 3 elements
    ['St', 'Sn', 'Th']
    >>> random.sample(days, 7)      # Choose 7 elements
    ['Tu', 'Th', 'Mo', 'We', 'St', 'Fr', 'Sn']
    >>> random.sample(days, 7)      # Choose 7 again
    ['We', 'Mo', 'Sn', 'Fr', 'Tu', 'St', 'Th']
    >>> random.sample(days, 8)      # Can't choose eight
    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)   # Choose ten odd nos. under 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 и делает код немного понятнее. Этот модуль не заставит многопоточный код работать без потоков; код, ожидающий возврата или выполнения какого-либо действия от другого потока, будет просто висеть вечно.

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

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

    import timeit
    
    timer1 = timeit.Timer('unicode("abc")')
    timer2 = timeit.Timer('"abc" + u""')
    
    # Run three trials
    print timer1.repeat(repeat=3, number=100000)
    print timer2.repeat(repeat=3, number=100000)
    
    # On my laptop this outputs:
    # [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 в false перед созданием первого объекта 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)      # See that other dictionary methods are implemented
    ['__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-вывод в определенной кодировке, предоставляя необязательный аргумент encoding методам toxml() и toprettyxml() узлов DOM.

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

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

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

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

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

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

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

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

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

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

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

>>> import datetime
>>> now = datetime.datetime.now()
>>> now.isoformat()
'2002-12-30T21:27:03.994956'
>>> now.ctime()  # Only available on date, datetime
'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

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

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

$ ./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. Аллокатор использует функцию malloc() языка Си для получения больших пулов памяти, а затем выполняет небольшие запросы памяти из этих пулов.

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

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

Есть одна особенно распространенная ошибка, которая вызывает проблемы. В C API Python есть ряд функций выделения памяти, которые раньше были просто псевдонимами для 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, используйте семейство «object» 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. Приведенная выше ссылка указывает на файл в SVN-браузере python.org.

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

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

  • Реализация обнаружения циклов, используемая сборщиком мусора, доказала свою стабильность, поэтому теперь она стала обязательной. Вы больше не сможете скомпилировать Python без нее, а переключатель --with-cycle-gc на configure был удален.

  • Теперь Python можно собирать как разделяемую библиотеку (libpython2.3.so), указав --enable-shared при запуске configure скрипта Python. (Внесено Ондреем Палковским.)

  • Макросы 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 теперь входит копия исходного кода XML-парсера Expat, что устраняет зависимость от системной версии или локальной установки Expat.

  • Если вы динамически выделяете объекты типа в своем расширении, вам следует знать об изменении правил, касающихся атрибутов __module__ и __name__. В общем, вы должны убедиться, что словарь типа содержит ключ '__module__'; то, что имя модуля является частью имени типа, предшествующей последней точке, больше не будет иметь желаемого эффекта. Для получения более подробной информации читайте справочную документацию по API или исходный текст.

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

Поддержка переноса на OS/2 от IBM с использованием среды выполнения EMX была включена в основное дерево исходных текстов Python. EMX - это слой эмуляции POSIX над системными API OS/2. Порт Python для EMX пытается поддерживать все POSIX-подобные возможности, предоставляемые средой выполнения EMX, и в основном преуспевает в этом; fork() и fcntl() ограничены ограничениями базового слоя эмуляции. Стандартный порт OS/2, использующий компилятор Visual Age от IBM, также получил поддержку чувствительной к регистру семантики импорта как часть интеграции порта 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, теперь содержат модуль и символ '.' перед именем типа.

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

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