Что нового в 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, такой как the Python Library Reference и the Python Reference Manual. Если вы хотите полностью разобраться в реализации и обосновании дизайна, обратитесь к PEP для получения информации о конкретной новой функции.

PEP 218: Стандартный набор типов данных

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

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

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

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

>>> S1 = sets.Set([1,2,3])
>>> S2 = sets.Set([4,5,6])
>>> S1.union(S2)
Set([1, 2, 3, 4, 5, 6])
>>> S1 | S2                  # 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 - Добавление встроенного набора типов объектов

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 ферзях (размещение N ферзей на NxN шахматной доске таким образом, чтобы ни один ферзь не угрожал другим ферзям) и об обходе коня (маршрут, по которому конь проходит на каждую клетку 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() возвращает индексы, в которых найдена подстрока «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: Поддержка имен файлов в юникоде для Windows NT

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

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

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

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

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

См.также

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

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

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

На сегодняшний день используются три основные операционные системы: Microsoft Windows, Macintosh OS от Apple и различные производные от Unix. Небольшая проблема кросс-платформенной работы заключается в том, что все эти три платформы используют разные символы для обозначения концов строк в текстовых файлах. В Unix используется перевод строки (символ ASCII 10), в Mac OS используется функция возврата каретки (символ 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(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 включает в себя обработчики, которые записывают записи журнала в standard error или в файл или сокет, отправляют их в системный журнал или даже отправляют по электронной почте на определенный адрес; конечно, также можно написать свои собственные классы обработчиков.

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

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

import logging

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

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

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

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

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

Существует также функция exception(), которая записывает самую последнюю обратную трассировку. Любая из других функций также будет записывать обратную трассировку, если вы укажете значение 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 был добавлен логический тип. В модуль __builtin__ были добавлены две новые константы: True и False. (константы True и False были добавлены во встроенные модули в Python 2.2.1, но в версиях 2.2.1 просто установлены целочисленные значения 1 и 0 и не имеют другого типа.)

Объект type для этого нового типа называется 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, также помешал бы вам выполнять арифметику с помощью Boolean и потребовал бы, чтобы выражение в операторе if всегда приводило к логическому результату. Python не настолько строг и никогда не будет таким, как явно сказано в PEP 285. Это означает, что вы все еще можете использовать любое выражение в if операторе, даже те, которые вычисляются как список, кортеж или какой-либо случайный объект. Тип Boolean является подклассом класса int, так что арифметика с использованием логического значения все еще работает.

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

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

См.также

PEP 285 - Добавление типа bool

Написана и реализована компанией GvR.

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

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

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

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

См.также

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

Написана и реализована Вальтером Дервальдом.

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

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

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

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

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

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 - Индекс пакета и метаданные для дистрибутивов

Написана и реализована Ричардом Джонсом.

PEP 302: Новые импортные крючки

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

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

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

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

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

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

Таким образом, псевдокод для новой логики импорта 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 и cPickle уделялось некоторое внимание в ходе цикла разработки версии 2.3. В версии 2.2 классы нового стиля можно было мариновать без труда, но они были маринованы не очень компактно; PEP 307 приводит тривиальный пример, в котором класс нового стиля приводит к маринованной строке в три раза длиннее, чем для классического класса.

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

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

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

В качестве способа еще большего сжатия pickles теперь можно использовать целочисленные коды вместо длинных строк для идентификации классов pickled. 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 типы list, tuple и string sequence никогда не поддерживали эту функцию, что приводило к появлению 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]

Теперь также можно передавать объекты slice в методы __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 теперь является типом object для типа slice и больше не является функцией. Это согласуется с версией Python 2.2, где int, str, и т.д. претерпели те же изменения.

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

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

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

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

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

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

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

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

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

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

  • В словарях появился новый метод pop(key[, *default*]), который возвращает значение, соответствующее ключу, и удаляет эту пару ключ/значение из словаря. Если запрошенный ключ отсутствует в словаре, возвращается значение 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__ ван -O Россум.)

  • new`(Автор :mod:`types - Джастин ван Россум.)

    >>> import types
    >>> m = types.ModuleType('abc','docstring')
    >>> m
    <module 'abc' (built-in)>
    >>> m.__doc__
    'docstring'
    
  • PendingDeprecationWarning`(Автор :option:-Walways::PendingDeprecationWarning:: <-W>` - Джастин 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() string.

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

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

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

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

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

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

    (Автор: Вальтер Дервальд.)

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

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

Оптимизация

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

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

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

  • Код операции 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 теперь поддерживает массивы символов Юникода, используя символ формата PyBSDDB. Массивы также теперь поддерживают использование оператора присваивания для добавления содержимого другого массива и оператора присваивания для повторения массива. (Автор Джейсон Орендорфф).

    Старая версия модуля была переименована в 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]. Это позволяет быстро удалить самый маленький элемент и вставить новый элемент, сохранив при этом свойство heap - O(log n). (Дополнительную информацию о структуре данных приоритетной очереди смотрите в разделе https://xlinux.nist.gov/dads//HTML/priorityque.html.)

    Модуль heapq предоставляет функции heappush() и heappop() для добавления и удаления элементов, сохраняя при этом свойство heap поверх некоторого другого изменяемого типа последовательности 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]
    

    (Автор: Кевин О’Коннор.)

  • ``reload()``(Автор: idlelib Кевин О’Коннор.)

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

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

  • math содержит ряд полезных функций для использования с итераторами, вдохновленных различными функциями, предоставляемыми языками ML и Haskell. Например, degrees(rads) возвращает все элементы в итераторе, для которых функция radians(degs) возвращает math, а math.sin() возвращает math.cos() N раз. math.log() В модуле e есть 10 ряд других функций; подробности смотрите в справочной документации к пакету. (Автор - Раймонд Хеттингер).

  • getpgid() содержит ряд полезных функций для использования с итераторами, вдохновленных различными функциями, предоставляемыми языками ML и Haskell. Например, killpg() возвращает все элементы в итераторе, для которых функция lchown() возвращает loadavg(), а major() возвращает makedev() N раз. minor() В модуле mknod() есть posix ряд os других функций; подробности смотрите в справочной документации к пакету. (Автор - Раймонд Хеттингер).

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

    В модуле stat_result семейство функций 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 tuple. Если эта функция используется, ее следует активировать на уровне приложения, а не пытаться включить ее для каждого пользователя.

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

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

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

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

  • Функция sample(population, k) была добавлена в модуль random. совокупность - это последовательность или 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) для объекта socket, чтобы установить время ожидания в 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() библиотеки platform C, а на разных платформах иногда возникают странные ошибки. Бретт Кэннон представил портативную реализацию, написанную на чистом Python и которая должна одинаково работать на всех платформах.

  • Новый модуль timeit помогает определить, сколько времени занимает выполнение фрагментов кода на Python. Файл timeit.py можно запустить непосредственно из командной строки или импортировать и использовать непосредственно класс модуля Timer. Вот краткий пример, который показывает, как быстрее преобразовать 8-разрядную строку в Unicode, добавив к ней пустую строку Unicode или используя функцию 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.

    Добавление mix-in в качестве суперкласса обеспечивает полный интерфейс словаря всякий раз, когда класс определяет __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, вы должны указать истинное значение для параметра allow_none при создании экземпляра Marshaller.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Есть одна особенно распространенная ошибка, которая вызывает проблемы. В C API Python есть ряд функций выделения памяти, которые ранее были просто псевдонимами для библиотеки C malloc() и free(), что означает, что если вы случайно вызовете несовпадающие функции, ошибка не будет заметна. Когда распределитель объектов включен, эти функции больше не являются псевдонимами malloc() и free(), и вызов неправильной функции для освобождения памяти может привести к дампу ядра. Например, если память была выделена с использованием PyObject_Malloc(), она должна быть освобождена с использованием:c:func: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 и связать его с исходным кодом для Python 2.3. источник вашего расширения.

См.также

https://hg.python.org/cpython/file/default/Objects/obmalloc.c

Для более подробной информации о реализации pymalloc см. в комментарии в верхней части файла Objects/obmalloc.c в исходном коде на языке Python. Выше ссылка указывает на файл в браузере python.org СВН.

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

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

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

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

  • Макросы DL_EXPORT и DL_IMPORT теперь являются устаревшими. Функции инициализации для модулей расширения Python теперь должны быть объявлены с использованием нового макроса PyMODINIT_FUNC, в то время как ядро Python обычно будет использовать макросы PyAPI_FUNC и PyAPI_DATA.

  • Интерпретатор можно скомпилировать без каких-либо инструкций для встроенных функций и модулей, указав --without-doc-strings в скрипте configure. Это уменьшит размер исполняемого файла Python примерно на 10%, но также будет означать, что вы не сможете получить помощь по встроенным функциям Python. (Автор: Густаво Нимейер).

  • Макрос PyArg_NoArgs() теперь устарел, и код, который его использует, должен быть изменен. Для Python 2.2 и более поздних версий таблица определения метода может указывать флаг METH_NOARGS, сигнализирующий об отсутствии аргументов, и тогда проверка аргументов может быть удалена. Если важна совместимость с версиями Python до версии 2.2, то вместо этого в коде можно использовать PyArg_ParseTuple(args, ""), но это будет медленнее, чем при использовании METH_NOARGS.

  • PyArg_ParseTuple() принимает символы нового формата для различных размеров целых чисел без знака: B для unsigned char, H для unsigned short int, I для : c:expr: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 parser, устраняя любую зависимость от версии системы или локальной установки Expat.

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

Изменения, связанные с конкретным портом

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

В Mac OS большинство модулей toolbox имеют слабую связь для улучшения обратной совместимости. Это означает, что модули больше не будут загружаться без сбоев, если в текущей версии ОС отсутствует какая-либо процедура. Вместо этого вызов отсутствующей процедуры вызовет исключение. (Автор: Джек Янсен).

Файлы спецификации 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 объектов frame, изменяя строку, которая будет выполняться следующей. В отладчик была добавлена команда jump, использующая pdb преимущества этой новой функции. (Реализована Ричи Хиндлом).

Перенос на Python 2.3

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

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

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

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

  • Если у вас есть строки в кодировке Unicode, содержащие 8-разрядные символы, вы должны указать кодировку файла (UTF-8, Latin1 или любую другую), добавив комментарий к началу файла. Дополнительную информацию смотрите в разделе 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() получила различные новые аргументы с ключевыми словами, такие как зависит. Старые версии Distutils будут отключены, если будут переданы неизвестные ключевые слова. Решение состоит в том, чтобы проверить наличие новой функции get_distutil_options() в вашем setup.py и использовать новые ключевые слова только в той версии дистрибутива, которая их поддерживает:

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

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

Признание

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

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