Что нового в 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 и date/time, возможность импорта модулей из архивов 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://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() возвращает индексы, в которых встречается подстрока «or»: 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 это будет синтаксической ошибкой.

Объявление кодировки влияет только на строковые литералы Unicode, которые будут преобразованы в Unicode с использованием указанной кодировки. Обратите внимание, что идентификаторы 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() передана строка Unicode, Python теперь возвращает список строк Unicode. Новая функция os.getcwdu() возвращает текущий каталог в виде строки Unicode.

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

Другие системы также допускают использование строк Unicode в качестве имен файлов, но преобразуют их в байтовые строки перед передачей в систему, что может привести к возникновению ошибки UnicodeError. Приложения могут проверить, поддерживаются ли произвольные строки Unicode в качестве имен файлов, проверив 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 при запуске скрипта 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]
    # ... 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(), которая записывает последний отслеженный откат. Любая из других функций также будет записывать отслеживание, если вы укажете истинное значение для аргумента ключевого слова 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 были не добавлены ради строгой проверки типов. Очень строгий язык, такой как Паскаль, также не позволит вам выполнять арифметические действия с булевыми числами и потребует, чтобы выражение в операторе 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: Обратные вызовы для обработки ошибок кодеков

При кодировании строки Unicode в байтовую строку могут встречаться некодируемые символы. До сих пор Python позволял задавать обработку ошибок как «строгую» (поднимая UnicodeError), «игнорировать» (пропуская символ) или «заменить» (используя вопросительный знак в выходной строке), причем «строгая» является поведением по умолчанию. Может быть желательно указать альтернативную обработку таких ошибок, например, вставка ссылки на символ 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 - CSV File API

Авторы и исполнители: Кевин Алтис, Дэйв Коул, Эндрю МакНамара, Скип Монтанаро, Клифф Уэллс.

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]

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

>>> 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 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-битные строки, так и строки Unicode, поэтому 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 включит буферизацию.

  • В модуль sample(population, k) была добавлена функция random. 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 в определенной кодировке, предоставляя необязательный аргумент кодировки методам toxml() и toprettyxml() узлов DOM.

  • Модуль xmlrpclib теперь поддерживает расширение XML-RPC для работы с нулевыми значениями данных, такими как Python None. Значения nil всегда поддерживаются при разгруппировке ответа 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 поддерживает Unicode 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), либо используя один из ряда методов класса. Например, метод класса date.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.

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

Изменения в процессе сборки 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 или исходный текст.

Изменения, относящиеся к конкретному порту

Поддержка переноса на 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 объектов frame, должны вместо этого вызывать PyCode_Addr2Line(f->f_code, f->f_lasti). Это даст дополнительный эффект и заставит код работать так, как нужно при команде «python -O» в более ранних версиях Python.

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

Перенос на Python 2.3

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

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

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

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

  • Если у вас есть строки Unicode, содержащие 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, теперь содержат модуль и символ '.' перед именем типа.

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

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

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