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

Автор

А.М. Кучлинг

Введение

В этой статье рассказывается о новых возможностях в Python 2.1. Хотя в версии 2.1 не так много изменений, как в Python 2.0, в ней все же есть несколько приятных сюрпризов. 2.1 - это первый выпуск, который был подготовлен с помощью предложений по улучшению Python, или PEPs, поэтому большинство значительных изменений сопровождаются PEPs, которые предоставляют более полную документацию и обоснование изменений. Эта статья не пытается полностью документировать новые возможности, а просто предоставляет обзор новых возможностей для программистов 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: __будущие__ директивы

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

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, а также делает взлом Make-файлов более понятным и простым.

См.также

PEP 229 - Использование Distutils для сборки Python

Написано и реализовано А.М. Кучлингом.

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

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

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

Например, рассмотрим функцию memoizing, которая кэширует результаты другой функции 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 функции помечаются как безопасные для публичного доступа благодаря наличию doc-строки, а в структуре синтаксического анализа SPARK Джона Эйкока doc-строки содержат части грамматики 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. Например, команды Distutils sdist и bdist_* могли бы поддерживать опцию 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, внесенный Тимом Питерсом, предоставляет структуру тестирования, основанную на выполнении встроенных примеров в docstrings и сравнении результатов с ожидаемым результатом. PyUnit, внесенный Стивом Перселлом, является основой для модульного тестирования, вдохновленной JUnit, который, в свою очередь, был адаптацией основы тестирования Smalltalk Кента Бека. Дополнительную информацию о PyUnit можно найти на сайте http://pyunit.sourceforge.net/.

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

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

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

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

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

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

  • Скорость линейно-ориентированного файлового ввода-вывода была улучшена, потому что люди часто жалуются на его недостаточную скорость, и потому что он часто использовался в качестве наивного эталона. Поэтому метод readline() в файловых объектах был переписан, чтобы стать намного быстрее. Точная величина ускорения будет варьироваться от платформы к платформе в зависимости от того, насколько медленным был getc() библиотеки Си, но она составляет около 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 и возвращает ее в виде кортежа. Эта функция была реализована в основном Тимом Питерсом и Гвидо ван Россумом, после предложения и предварительных исправлений Моше Задки.

  • Модули теперь могут контролировать, какие имена импортируются при использовании 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).

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

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

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

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