Что нового в 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):
    "Return list of any entries equal to '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():
    # The next line is a syntax error
    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__ Directives

Реакция на вложенные диапазоны была широко распространенной озабоченностью опасностью сломать код в релизе 2.1, и она была достаточно сильной, чтобы заставить питонеров принять более консервативный подход. Этот подход заключается во введении соглашения о включении необязательной функциональности в выпуске 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., &c. Программисты-числовики почти наверняка хорошо знакомы с этими именами и легко их запомнят).

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

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

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

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

См.также

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

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

См.также

PEP 5 - Руководство по эволюции языка

Написан Полом Прескодом, чтобы определить процедуры, которым следует следовать при удалении старых функций из Python. Политика, описанная в этом PEP, не была официально принята, но возможная политика, вероятно, не будет сильно отличаться от предложения Прескода.

PEP 230 - Предупреждение Framework

Написана и реализована Гвидо ван Россумом.

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 использует один нерекурсивный makefile, а не makefile в верхнем каталоге и в каждом из подкаталогов Python/, Parser/, Objects/ и Modules/. Это ускоряет сборку Python, а также делает взлом Makefile’ов более понятным и простым.

См.также

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 the returned object
    _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 weak reference object still exists,
        # return it
        if obj is not None: return obj

    retval = f(x)

    # Cache a weak reference
    _cache[x] = weakref.ref(retval)

    return retval

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

proxy = weakref.proxy(obj)
proxy.attr   # Equivalent to obj.attr
proxy.meth() # Equivalent to obj.meth()
del obj
proxy.attr   # raises weakref.ReferenceError

См.также

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

Написано и реализовано Фредом Л. Дрейком-младшим.

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

В Python 2.1 к функциям теперь можно прикреплять произвольную информацию. Для хранения информации о функциях и методах люди часто использовали docstrings, поскольку атрибут __doc__ был единственным способом прикрепить к функции какую-либо информацию. Например, в сервере веб-приложений Zope функции помечаются как безопасные для публичного доступа благодаря наличию docstring, а во фреймворке для разбора SPARK Джона Эйкока docstrings содержит части BNF-грамматики для разбора. Такая перегрузка неудачна, поскольку docstrings на самом деле предназначены для хранения документации функции; например, это означает, что вы не можете правильно документировать функции, предназначенные для частного использования в 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(). Например, вы можете установить ее на специальную функцию красивой печати:

>>> # Create a recursive data structure
... L = [1,2,3]
>>> L.append(L)
>>> L # Show Python's default output
[1, 2, 3, [...]]
>>> # Use pprint.pprint() as the display function
... 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 singleton. Затем будут опробованы числовые функции другого типа, и, возможно, они смогут обработать эту операцию; если другой тип также возвращает Py_NotImplemented, то будет вызвана ошибка TypeError. Числовые методы, написанные на Python, также могут возвращать Py_NotImplemented, заставляя интерпретатор действовать так, как будто метода не существует (возможно, вызывая TypeError, возможно, пробуя числовые методы другого объекта).

См.также

PEP 208 - Переработка модели принуждения

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

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

Пользователи Python часто жалуются на то, что нет единого каталога всех существующих модулей Python. Vaults of Parnassus Т. Миддлтона по адресу www.vex.net/parnassus/ (прекратил существование в феврале 2009 года, available in the Internet Archive Wayback Machine) был самым большим каталогом модулей Python, но регистрация программ в Vaults необязательна, и многие люди не стали этим заниматься.

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

Вы можете начать создавать пакеты, содержащие PKG-INFO, даже если вы не используете Python 2.1, так как новый выпуск Distutils будет сделан для пользователей более ранних версий Python. Версия 1.0.2 Distutils включает в себя изменения, описанные в PEP 241, а также различные исправления и улучшения. Она будет доступна в Distutils SIG по адресу https://www.python.org/community/sigs/current/distutils-sig/.

См.также

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 Кента Бека. Дополнительную информацию о PyUnit можно найти на сайте https://pyunit.sourceforge.net/.

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

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

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

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

  • Различные функции в модуле time, такие как asctime() и localtime(), требуют аргумент с плавающей точкой, содержащий время в секундах с момента наступления эпохи. Чаще всего эти функции используются для работы с текущим временем, поэтому аргумент с плавающей точкой был сделан необязательным; если значение не указано, будет использоваться текущее время. Например, в записях лог-файлов обычно требуется строка, содержащая текущее время; в 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() и иметь меньшие накладные расходы памяти. Аллокатор использует функцию malloc() языка C для получения больших пулов памяти, а затем выполняет небольшие запросы памяти из этих пулов. Его можно включить, указав опцию --with-pymalloc в скрипте configure; подробности реализации см. в Objects/obmalloc.c.

    Авторам модулей расширения C следует протестировать свой код с включенным аллокатором объектов, потому что некоторый некорректный код может сломаться, что приведет к дампам ядра во время выполнения. В C API Python есть куча функций выделения памяти, которые раньше были просто псевдонимами для 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():
        # ... do something for each line ...
        ...
    

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

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

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

    # List public names
    __all__ = ['Database', 'open']
    

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

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

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

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

  • Размер базы данных символов Unicode уменьшился еще на 340K благодаря Фредрику Лунду.

  • Были добавлены некоторые новые порты: MacOS X (автор Steven Majewski), Cygwin (автор Jason Tishler); RISCOS (автор Dietmar Schwertberger); Unixware 7 (автор Billy G. Allie).

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

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

Автор хотел бы поблагодарить следующих людей за предложения по различным черновикам этой статьи: Graeme Cross, David Goodger, Jay Graves, Michael Hudson, Marc-André Lemburg, Fredrik Lundh, Neil Schemenauer, Thomas Wouters.