Что нового в Python 2.1

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

Вступление

В этой статье объясняются новые возможности Python 2.1. Хотя в версии 2.1 не так много изменений, как в Python 2.0, все же есть несколько приятных сюрпризов. 2.1 — это первый релиз, управляемый с помощью предложений по улучшению Python, или PEP, поэтому большинство значительных изменений сопровождаются PEP, которые предоставляют более полную документацию и обоснование дизайна для изменения. В этой статье не делается попытка полностью задокументировать новые функции, а просто представлен обзор новых функций для программистов Python. Обратитесь к документации Python 2.1 или к PEP, чтобы получить дополнительные сведения о любой новой функции, которая вас особенно интересует.

Одна из недавних целей команды разработчиков Python заключалась в том, чтобы ускорить релиз новых релизов, при этом новый релиз выходит каждые 6–9 месяцев. 2.1 — это первый релиз, который выходит в таком быстром темпе: первая альфа-версия появилась в январе, через 3 месяца после релиза финальной версии 2.0.

Окончательный релиз Python 2.1 был выпущен 17 апреля 2001 года.

PEP 227: Вложенные области

Самое большое изменение в Python 2.1 касается правил области видимости Python. В Python 2.0 в любой момент времени для поиска имён переменных используются не более трех пространств имён: локальное, на уровне модуля и встроенное пространство имён. Это часто удивляло людей, потому что не соответствовало их интуитивным ожиданиям. Например, определение вложенной рекурсивной функции не работает:

def f():
    ...
    def g(value):
        ...
        return g(value-1) + 1
    ...

Функция g() всегда будет вызывать исключение NameError, поскольку привязка имени g не находится ни в её локальном пространстве имён, ни в пространстве имён уровня модуля. На практике это не представляет большой проблемы (как часто вы рекурсивно определяете внутренние функции подобным образом?), но это также делало использование выражения lambda более неуклюжим, и на практике это было проблемой. В коде, который использует lambda, вы часто можете обнаружить, что локальные переменные копируются, передавая их в качестве значений аргументов по умолчанию.

def find(self, name):
    "Возвращает список любых записей, равных 'name'"
    L = filter(lambda x, name=name: x == name,
               self.list_attribute)
    return L

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

Наиболее значительным изменением в Python 2.1 является то, что для решения этой проблемы в язык была добавлена статическая область видимости. Во-первых, в приведённом выше примере аргумент по умолчанию name=name теперь не нужен. Проще говоря, когда заданному имени переменной не присваивается значение внутри функции (присваиванием или операторами def, class или import), ссылки на переменную будут искаться в локальном пространстве имён объемлющей области. Более подробное объяснение правил и разбор реализации можно найти в PEP.

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

Одним из побочных эффектов изменения является то, что операторы from module import * и exec стали недопустимыми внутри области действия функции при определенных условиях. В справочном руководстве по Python все время говорилось, что from module import * допустим только на верхнем уровне модуля, но интерпретатор CPython никогда раньше не применял это. В рамках реализации вложенных областей компилятор, который превращает исходный код Python в байт-коды, должен генерировать другой код для доступа к переменным в содержащей области. from module import * и exec не позволяют компилятору понять это, потому что они добавляют имена в локальное пространство имён, которые неизвестны во время компиляции. Поэтому, если функция содержит определения функций или выражения lambda со свободными переменными, компилятор отметит это, вызвав исключение SyntaxError.

Чтобы сделать предыдущее объяснение немного яснее, вот пример:

x = 1
def f():
    # В следующей строке синтаксическая ошибка
    exec 'x=2'
    def g():
        return x

Строка 4, содержащая оператор exec, является синтаксической ошибкой, поскольку exec определяет новую локальную переменную с именем x, к значению которой должен обращаться g().

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

Проблемы совместимости привели к постепенному внедрению вложенных областей; в Python 2.1 они не включены по умолчанию, но их можно включить в модуле с помощью оператора future, как приведено в PEP 236. (Дальнейшее обсуждение PEP 236 см. в следующем разделе.) В Python 2.2 вложенные области станут стандартными, и их нельзя будет отключить, но у пользователей будет весь срок службы версии 2.1, чтобы исправить любую поломку, возникшую в результате их введение.

См.также

PEP 227 — статически вложенные области
Написано и реализовано Джереми Хилтоном.

PEP 236: __future__ директивы

Реакцией на вложенные области видимости была широко распространенная озабоченность по поводу опасности взлома кода в выпуске 2.1, и она была достаточно сильной, чтобы заставить разработчиков Python занять более консервативный подход. Данный подход состоит во введении соглашения о включении дополнительных функций в выпуске N, которые станут обязательными в выпуске N+1.

В синтаксисе используется оператор from...import с использованием зарезервированного имени модуля __future__. Вложенные области можно включить с помощью следующего оператора:

from __future__ import nested_scopes

Хотя это выглядит как обычный оператор import, это не так; существуют строгие правила относительно того, где можно разместить такое заявление о будущем. Они могут находиться только в начале модуля и должны предшествовать любому коду Python или обычным операторам import. Это связано с тем, что такие операторы могут повлиять на то, как компилятор байт-кода Python анализирует код и генерирует байт-код, поэтому они должны предшествовать любому оператору, который приведёт к созданию байт-кода.

См.также

PEP 236 — вернуться к __future__
Написано Тимом Питерсом и в основном реализовано Джереми Хилтоном.

PEP 207: Богатые сравнения

В более ранних версиях поддержка Python для реализации сравнений в определяемых пользователем классах и типах расширений была довольно простой. Классы могли реализовать метод __cmp__(), который получал два экземпляра класса и мог возвращать только 0, если они равны, или +1 или -1, если они не равны; метод не мог вызвать исключение или возвращает что-либо, кроме логического значения. Пользователи Numeric Python часто находили эту модель слишком слабой и ограничительной, потому что в программах обработки чисел, для которых используется numeric Python, было бы полезнее иметь возможность выполнять поэлементное сравнение двух матриц, возвращая матрицу, содержащую результаты заданное сравнение для каждого элемента. Если две матрицы имеют разный размер, то сравнение должно иметь возможность вызвать исключение, чтобы сигнализировать об ошибке.

В Python 2.1 были добавлены расширенные сравнения, чтобы удовлетворить эту потребность. Классы Python теперь могут по отдельности перегружать каждую из операций <, <=, >, >=, == и !=. Названия новых магических методов:

Операция Название метода
< __lt__()
<= __le__()
> __gt__()
>= __ge__()
== __eq__()
!= __ne__()

(Магические методы названы в честь соответствующих операторов Фортрана .LT., .LE. и т. д. Программистам, работающим с числами, почти наверняка хорошо знакомы данные имена, и они легко их запомнят.)

У каждого из данных магических методов форма method(self, other), где self будет объектом слева от оператора, а other будет объектом справа. Например, выражение A < B приведёт к вызову A.__lt__(B).

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

Встроенная функция cmp(A,B) может использовать расширенный механизм сравнения и теперь принимает необязательный аргумент, указывающий, какую операцию сравнения использовать; это задается как одна из строк "<", "<=", ">", ">=", "==" или "!=". При вызове без дополнительного третьего аргумента cmp() вернёт только -1, 0 или +1, как в предыдущих версиях Python; в противном случае он вызовет соответствующий метод и может возвращает любой объект Python.

Есть также соответствующие изменения, представляющие интерес для программистов на C; есть новый слот tp_richcmp в объектах типа и API для выполнения данного расширенного сравнения. Я не буду рассматривать здесь C API, а отсылаю вас к PEP 207 или к документации по C API версии 2.1 для получения полного списка связанных функций.

См.также

PEP 207 — Богатые сравнения
Написано Гвидо ван Россумом, в значительной степени основано на более ранних работах Дэвида Ашера реализованный Гвидо ван Россумом.

PEP 230: Система предупреждений

За 10 лет своего существования Python накопил определенное количество устаревших модулей и фич. Трудно понять, когда можно безопасно удалить функцию, поскольку невозможно узнать, сколько кода её использует. Для более структурированного удаления старых функций была добавлена система предупреждений. Когда разработчики Python хотят избавиться от какой-либо функции, она сначала вызывает предупреждение в следующей версии Python. В следующей версии Python данная функция может быть удалена, и у пользователей будет полный цикл релиза, чтобы удалить использование старой функции.

Python 2.1 добавляет структуру предупреждений для использования в этой схеме. Он добавляет модуль warnings, предоставляющий функции для выдачи предупреждений и фильтрации предупреждений, которые вы не хотите отображать. Сторонние модули также могут использовать эту структуру для отказа от старых функций, которые они больше не хотят поддерживать.

Например, в Python 2.1 модуль regex устарел, поэтому его импорт приводит к выводу предупреждения:

>>> import regex
__main__:1: DeprecationWarning: the regex module
         is deprecated; please use the re module
>>>

Предупреждения могут быть выданы вызовом функции warnings.warn():

warnings.warn("feature X no longer supported")

Первый параметр — это предупреждающее сообщение; дополнительные необязательные параметры могут использоваться для указания категории предупреждений.

Можно добавить фильтры для отключения определенных предупреждений; шаблон регулярного выражения может быть применен к сообщению или к имени модуля, чтобы подавить предупреждение. Например, у вас может быть программа, использующая модуль regex, и вы не хотите тратить время на преобразование её для использования модуля re прямо сейчас. Предупреждение можно подавить, вызвав

import warnings
warnings.filterwarnings(action = 'ignore',
                        message='.*regex module is deprecated',
                        category=DeprecationWarning,
                        module = '__main__')

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

В C API Python также были добавлены функции для выдачи предупреждений; подробности см. в PEP 230 или в документации API Python.

См.также

PEP 5 — Рекомендации по развитию языка
Написано Полом Прескодом, чтобы указать процедуры, которым необходимо следовать при удалении старого функции из Python. Политика, описанная в этом PEP, официально не применялась принята, но конечная политика, вероятно, не будет слишком отличаться от политики Prescod предложение.
PEP 230 — Система предупреждений
Написано и реализовано Гвидо ван Россумом.

PEP 229: Новая система сборки

При компиляции Python пользователю приходилось заходить и редактировать файл Modules/Setup, чтобы включить различные дополнительные модули; множество по умолчанию относительно невелик и ограничен модулями, которые компилируются на большинстве платформ Unix. Это означает, что на платформах Unix со многими другими функциями, в первую очередь на Linux, установки Python часто не содержат всех полезных модулей, которые могли бы быть.

Python 2.0 добавил Distutils, множество модулей для распространения и установки расширений. В Python 2.1 Distutils используются для компиляции большей части стандартной библиотеки модулей расширения, автоматически определяя, какие из них поддерживаются на текущей машине. Есть надежда, что это упростит установку Python и сделает её более функциональной.

Вместо редактирования файла Modules/Setup, чтобы включить модули, сценарий setup.py в верхнем каталоге исходного дистрибутива Python запускается во время сборки и пытается определить, какие модули можно включить, изучая модули и файлы заголовков на система. Если модуль настроен в Modules/Setup, сценарий setup.py не будет пытаться скомпилировать данный модуль и будет ссылаться на содержимое файла Modules/Setup. Это позволяет указать любые странные флаги командной строки или библиотеки, необходимые для платформы.

Другим далеко идущим изменением механизма сборки стало то, что Нил Шеменауэр реструктурировал вещи так, что теперь Python использует один make-файл, который не является рекурсивным, вместо make-файлов в верхнем каталоге и в каждом из подкаталогов Python/, Parser/, Objects/ и Modules/. Это ускоряет сборку Python, а также делает хакинг Makefiles более понятным и простым.

См.также

PEP 229 — Использование Distutils для сборки Python
Написано и реализовано А.М. Кухлинг.

PEP 205: Слабые ссылки

Слабые ссылки, доступные через модуль weakref, являются второстепенным, но полезным новым типом данных в множестве инструментов программиста Python.

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

Например, рассмотрим функцию запоминания, которая кэширует результаты другой функции f(x), сохраняя аргумент функции и её результат в словаре:

_cache = {}
def memoize(x):
    if _cache.has_key(x):
        return _cache[x]

    retval = f(x)

    # Кэшировать возвращаемый объект
    _cache[x] = retval

    return retval

Версия работает для простых вещей, таких как целые числа, но имеет побочный эффект; словарь _cache содержит ссылку на возвращаемые значения, поэтому они никогда не будут освобождены, пока процесс Python не завершится и не очистится. Это не очень заметно для целых чисел, но если f() возвращает объект или структуру данных, которая занимает много памяти, это может стать проблемой.

Слабые ссылки предоставляют способ реализации кэша, который не будет поддерживать жизнь объектов дольше их времени. Если объект доступен только через слабые ссылки, объект будет освобожден, а слабые ссылки теперь будут указывать на то, что объект, на который он ссылался, больше не существует. Слабая ссылка на объект obj создаётся вызовом wr = weakref.ref(obj). Объект, на который делается ссылка, возвращается путём вызова слабой ссылки, как если бы это была функция: wr(). Он вернёт указанный объект или None, если объект больше не существует.

Это позволяет написать функцию memoize(), кеш которой не поддерживает объекты живыми, сохраняя в кеше слабые ссылки.

_cache = {}
def memoize(x):
    if _cache.has_key(x):
        obj = _cache[x]()
        # Если объект слабой ссылки все ещё существует,
        # возвращает его
        if obj is not None: return obj

    retval = f(x)

    # Кэшировать слабую ссылку
    _cache[x] = weakref.ref(retval)

    return retval

Модуль weakref также позволяет создавать прокси-объекты, которые ведут себя как слабые ссылки. — объект, на который ссылаются только прокси-объекты, освобождается, но вместо того, чтобы требовать явного вызова для извлечения объекта, прокси-сервер прозрачно перенаправляет все операции объекту до тех пор, пока объект все ещё существует. Если объект освобожден, попытка использовать прокси вызовет исключение weakref.ReferenceError.

proxy = weakref.proxy(obj)
proxy.attr   # Эквивалентно obj.attr
proxy.meth() # Эквивалентно obj.meth()
del obj
proxy.attr   # вызывает weakref.ReferenceError

См.также

PEP 205 — Слабые ссылки
Написано и реализовано Фредом Л. Дрейком-младшим.

PEP 232: Атрибуты функций

В Python 2.1 к функциям теперь может быть присоединена произвольная информация. Люди часто использовали строки документации для хранения информации о функциях и методах, потому что атрибут __doc__ был единственным способом прикрепить какую-либо информацию к функции. Например, на сервере веб-приложений Zope функции помечены как безопасные для публичного доступа с помощью строки документации, а в среде синтаксического анализа SPARK Джона Эйкока строки документации содержат части грамматики BNF для анализа. Перегрузка досадна, т. к. строки документации действительно предназначены для хранения документации функции; например, это означает, что вы не можете должным образом документировать функции, предназначенные для частного использования в Zope.

Произвольные атрибуты теперь можно устанавливать и извлекать в функциях с использованием обычного синтаксиса Python:

def f(): pass

f.publish = 1
f.secure = 1
f.grammar = "A ::= B (C D)*"

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

См.также

PEP 232 — Атрибуты функций
Написано и реализовано Барри Варшавой.

PEP 235: Импорт модулей на платформы без учёта регистра

В некоторых операционных системах файловые системы нечувствительны к регистру, основными примерами являются MacOS и Windows; в данных системах невозможно различить имена файлов FILE.PY и file.py, даже несмотря на то, что они сохраняют имя файла в исходном регистре (они также сохраняют регистр).

В Python 2.1 оператор import будет работать для имитации учета регистра на платформах, нечувствительных к регистру. Python теперь будет искать первое совпадение с учётом регистра по умолчанию, поднимая ImportError, если такой файл не найден, поэтому import file не будет импортировать модуль с именем FILE.PY. Сопоставление без учета регистра можно запросить, установив переменную среды PYTHONCASEOK перед запуском интерпретатора Python.

PEP 217: Интерактивный дисплейный хук

При интерактивном использовании интерпретатора Python вывод команд отображается с помощью встроенной функции repr(). В Python 2.1 переменная sys.displayhook() может быть установлена на вызываемый объект, который будет вызываться вместо repr(). Например, вы можете настроить его на специальную функцию красивой печати:

>>> # Создать рекурсивную структуру данных
... L = [1,2,3]
>>> L.append(L)
>>> L # Показать вывод Python по умолчанию
[1, 2, 3, [...]]
>>> # Использование pprint.pprint() в качестве функции отображения
... import sys, pprint
>>> sys.displayhook = pprint.pprint
>>> L
[1, 2, 3,  <Recursion on list with id=135143996>]
>>>

См.также

PEP 217 — хук для интерактивного использования
Написано и реализовано Моше Задкой.

PEP 208: Новая модель принуждения

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

Типы расширений теперь могут устанавливать флаг типа Py_TPFLAGS_CHECKTYPES в своей структуре PyTypeObject, чтобы указать, что они поддерживают новую модель принуждения. В таких типах расширения функции числового слота больше не могут предполагать, что им будут переданы два аргумента одного и того же типа; вместо этого им могут быть переданы два аргумента разных типов, а затем они могут выполнять собственное внутреннее принуждение. Если функции слота передаётся тип, который она не может обработать, она может указать на ошибку, вернув ссылку на одноэлементное значение Py_NotImplemented. Затем будут опробованы числовые функции другого типа, и, возможно, они справятся с этой операцией; если другой тип также возвращает Py_NotImplemented, то будет вызвано TypeError. Числовые методы, написанные на Python, также могут возвращать Py_NotImplemented, заставляя интерпретатор действовать так, как если бы метод не существовал (возможно, вызывая TypeError, возможно, пробуя числовые методы другого объекта).

См.также

PEP 208 — Переработка модели принуждения
Написано и реализовано Нилом Шеменауэром, в значительной степени основано на более ранних работах Марк-Андре Лембург. Прочитать это, чтобы понять тонкости числовых значений операции теперь будут обрабатываться на уровне C.

PEP 241: метаданные в пакетах Python

Распространенная жалоба пользователей Python заключается в том, что не существует единого каталога всех существующих модулей Python. Т. Миддлтон «Своды Парнаса» http://www.vex.net/parnassus/ — это самый большой каталог модулей Python, но регистрация программного обеспечения в Vaults необязательна, и многие люди не беспокоятся об этом.

В качестве первого небольшого шага к устранению проблемы программное обеспечение Python, упакованное с помощью команды Distutils sdist, будет включать файл с именем PKG-INFO, содержащий информацию о пакете, такую как его имя, версия и автор (метаданные в терминологии каталогизации). PEP 241 содержит полный список полей, которые могут присутствовать в файле PKG-INFO. По мере того как люди начали упаковывать свое программное обеспечение с помощью Python 2.1, все больше и больше пакетов будут включать метаданные, что позволит создавать автоматизированные системы каталогизации и экспериментировать с ними. С полученным опытом, возможно, удастся разработать действительно хороший каталог, а затем встроить его поддержку в Python 2.2. Например, команды Distutils sdist и bdist_* могут поддерживать параметр upload, который будет автоматически загружать ваш пакет на сервер каталогов.

Вы можете начать создавать пакеты, содержащие PKG-INFO, даже если вы не используете Python 2.1, поскольку для пользователей более ранних версий Python будет выпущен новый релиз Distutils. Версия 1.0.2 Distutils включает изменения, описанные в PEP 241, а также различные исправления и улучшения. Он будет доступен в SIG Distutils по адресу.

См.также

PEP 241 — метаданные для программных пакетов Python
Написано и реализовано А.М. Кухлинг.
PEP 243 — Механизм загрузки репозитория модулей
Данный проект PEP, написанный Шоном Райфшнайдером, предлагает механизм загрузки Python пакетов на центральный сервер.

Новые и улучшенные модули

  • Ка-Пинг Йи предоставил два новых модуля: inspect.py, модуль для получения информации о реальном коде Python, и pydoc.py, модуль для интерактивного преобразования строк документации в HTML или текст. В качестве бонуса Tools/scripts/pydoc, который теперь устанавливается автоматически, использует pydoc.py для отображения документации с заданным именем модуля, пакета или класса Python. Например, pydoc xml.dom отображает следующее:

    Python Library Documentation: package xml.dom in xml
    
    NAME
        xml.dom - W3C Document Object Model implementation for Python.
    
    FILE
        /usr/local/lib/python2.1/xml/dom/__init__.pyc
    
    DESCRIPTION
        The Python mapping of the Document Object Model is documented in the
        Python Library Reference in the section on the xml.dom package.
    
        This package contains the following modules:
          ...
    

    pydoc также включает браузер интерактивной справки на основе Tk. pydoc быстро вызывает привыкание; попробуй!

  • В стандартную библиотеку добавлены два разных модуля для модульного тестирования. Модуль doctest, предоставленный Тимом Питерсом, предоставляет платформу тестирования, основанную на выполнении встроенных примеров в строках документации и сравнении результатов с ожидаемыми результатами. PyUnit, предоставленный Стивом Перселлом, представляет собой среду модульного тестирования, вдохновленную JUnit, которая, в свою очередь, была адаптацией среды тестирования Smalltalk Кента Бека. См. http://pyunit.sourceforge.net/ для получения дополнительной информации о PyUnit.

  • Модуль difflib содержит класс SequenceMatcher, который сравнивает две последовательности и вычисляет изменения, необходимые для преобразования одной последовательности в другую. Например, данный модуль можно использовать для написания инструмента, аналогичного программе Unix diff, и фактически пример программы Tools/scripts/ndiff.py демонстрирует, как написать такой сценарий.

  • curses.panel, оболочка для библиотеки панелей, входящая в состав ncurses и curses SYSV, была предоставлена Томасом Геллекумом. Библиотека панелей предоставляет окнам дополнительную функцию глубины. Окна можно перемещать выше или ниже в порядке глубины, а библиотека панелей определяет, где панели перекрываются и какие секции видны.

  • Пакет PyXML претерпел несколько релизов, начиная с Python 2.0, а Python 2.1 включает обновленную версию пакета xml. Некоторые из заслуживающих внимания изменений включают поддержку Expat 1.2 и более поздних версий, возможность парсеров Expat обрабатывать файлы в любой кодировке, поддерживаемой Python, а также различные исправления ошибок для SAX, DOM и модуля minidom.

  • Ping также предоставил ещё один хук для обработки неперехваченных исключений. sys.excepthook() может быть установлен как вызываемый объект. Когда исключение не перехвачено ни одним из блоков tryexcept, исключение будет передано в sys.excepthook(), который затем может делать все, что захочет. На девятой конференции Python Пинг продемонстрировал применение этого хука: распечатку расширенной трассировки, которая не только перечисляет фреймы стека, но также перечисляет аргументы функции и локальные переменные для каждого фрейма.

  • Функции asctime() и localtime() в модуле time, требуют аргумента с плавающей запятой, содержащего время в секундах с начала эпохи. Чаще всего данные функции используются для работы с текущим временем, поэтому аргумент с плавающей запятой стал необязательным; если значение не указано, будет использоваться текущее время. Например, для записей файла журнала обычно требуется строка, содержащая текущее время; в Python 2.1 можно использовать time.asctime() вместо более длинного time.asctime(time.localtime(time.time())), который требовался ранее.

    Это изменение было предложено и реализовано Томасом Воутерсом.

  • Модуль ftplib теперь по умолчанию извлекает файлы в пассивном режиме, поскольку пассивный режим с большей вероятностью будет работать из-за брандмауэра. Данный запрос поступил от системы отслеживания ошибок Debian, поскольку другие пакеты Debian используют ftplib для извлечения файлов, а затем не работают из-за брандмауэра. Маловероятно, что это вызовет проблемы у кого-либо, поскольку Netscape по умолчанию использует пассивный режим, и мало кто жалуется, но если пассивный режим не подходит для вашего приложения или настройки сети, вызвать set_pasv(0) на объектах FTP, чтобы отключить пассивный режим.

  • В модуль socket добавлена поддержка необработанного доступа к сокетам, предоставленная Грантом Эдвардсом.

  • Модуль pstats теперь содержит простой интерактивный браузер статистики для отображения профилей времени для программ Python, вызываемый при запуске модуля как скрипта. Предоставлено Эриком С. Рэймондом.

  • Добавлена новая зависящая от реализации функция sys._getframe([depth]) для возврата заданного объекта фрейма из текущего стека вызовов. sys._getframe() возвращает фрейм наверху стека вызовов; если указан необязательный целочисленный аргумент depth, функция возвращает фрейм, который является вызовом depth ниже вершины стека. Например, sys._getframe(1) возвращает объект фрейма вызывающего объекта.

    Данная функция присутствует только в CPython, но не в Jython или реализации .NET. Используйте её для отладки и не поддавайтесь искушению внедрить её в производственный код.

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

В Python 2.1 было внесено относительно немного небольших изменений из-за более короткого цикла релиза. Поиск в журналах изменений CVS выявил 117 примененных исправлений и 136 исправленных ошибок; обе цифры, вероятно, занижены. Некоторые из наиболее заметных изменений:

  • Опционально доступен специализированный распределитель объектов, который должен работать быстрее, чем системный malloc(), и иметь меньшую нагрузку на память. Распределитель использует функцию C malloc() для получения больших пулов памяти, а затем выполняет меньшие запросы памяти из данных пулов. Его можно включить, указав параметр --with-pymalloc для сценария configure; подробности реализации см. в Objects/obmalloc.c.

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

    Распределитель объектов предоставил Владимир Марангозов.

  • Скорость построчного файлового ввода-вывода была улучшена, потому что люди часто жалуются на недостаточную скорость, а также потому, что его часто использовали в качестве наивного эталона. Поэтому метод файловых объектов readline() был переписан, чтобы стать намного быстрее. Точная величина ускорения будет варьироваться от платформы к платформе в зависимости от того, насколько медленным был getc() библиотеки C, но составляет около 66% и потенциально намного быстрее в некоторых операционных системах. Тим Питерс сделал большую часть бенчмаркинга и кодирования для этого изменения, мотивированного обсуждением в comp.lang.python.

    Также были добавлены новый модуль и метод для файловых объектов, предоставленные Джеффом Эплером. Новый метод xreadlines() аналогичен существующему встроенному методу xrange(). xreadlines() возвращает непрозрачный объект последовательности, который поддерживает только повторение, чтение строки на каждой итерации, но не чтение всего файла в память, как это делает существующий метод readlines(). Вы бы использовали это так:

    for line in sys.stdin.xreadlines():
        # ... сделать что-то для каждой строки ...
        ...
    

    Для более полного обсуждения изменений линейного ввода-вывода см. сводку python-dev за 1–15 января 2001 г. по адресу https://mail.python.org/pipermail/python-dev/2001-January/.

  • В словари был добавлен новый метод popitem(), позволяющий деструктивно перебирать содержимое словаря; это может быть быстрее для больших словарей, потому что нет необходимости создавать список, содержащий все ключи или значения. D.popitem() удаляет случайную пару (key, value) из словаря D и возвращает её как двойку. Это было реализовано в основном Тимом Петерсом и Гвидо ван Россумом после предложения и предварительного исправления Моше Задки.

  • Модули теперь могут контролировать, какие имена импортируются при использовании from module import *, путём определения атрибута __all__, содержащего список имён, которые будут импортированы. Одна из распространенных жалоб заключается в том, что если модуль импортирует другие модули, например sys или string, from module import * добавит их в пространство имён импортирующего модуля. Чтобы исправить это, просто перечислите общедоступные имена в __all__:

    # Список общедоступных имён
    __all__ = ['Database', 'open']
    

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

  • Применение repr() к строкам, ранее использовавшим восьмеричные escape- последовательности для непечатаемых символов; например, новая строка была '\012'. Это был рудиментарный след предков Python C, но сегодня восьмеричный язык имеет очень мало практического применения. Ка-Пинг Йи предложил использовать шестнадцатеричные escape-последовательности вместо восьмеричных и использовать escape-последовательности \n, \t, \r для соответствующих символов и внедрил это новое форматирование.

  • Синтаксические ошибки, обнаруженные во время компиляции, теперь могут вызывать исключения, содержащие имя файла и номер строки ошибки, что является приятным побочным эффектом реорганизации компилятора, выполненной Джереми Хилтоном.

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

  • Размер базы данных символов Юникод сократился ещё на 340 КБ благодаря Фредрику Лунду.

  • Были представлены некоторые новые порты: MacOS X (от Стивена Маевски), Cygwin (от Джейсона Тишлера); RISCOS (Дитмар Швертбергер); Unixware 7 (автор Билли Г. Элли).

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

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

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