Что нового в Python 2.0

Автор:

А.М. Кюхлинг и Моше Задка

Введение

Новый релиз Python, версия 2.0, был выпущен 16 октября 2000 года. В этой статье мы расскажем о новых интересных функциях в версии 2.0, отметим некоторые другие полезные изменения, а также укажем на несколько несовместимых изменений, которые могут потребовать переписывания кода.

Развитие Python никогда не останавливается между выпусками, и в него постоянно поступает поток исправлений и улучшений. В 2.0 вошло множество мелких исправлений, несколько оптимизаций, дополнительные документообороты и улучшенные сообщения об ошибках; перечислить их все было бы невозможно, но они, безусловно, значительны. Если вы хотите ознакомиться с полным списком, обратитесь к общедоступным CVS-журналам. Этот прогресс объясняется тем, что пять разработчиков, работающих в PythonLabs, теперь получают деньги за то, что тратят свои дни на исправление ошибок, а также улучшением коммуникации в результате перехода на SourceForge.

Что насчет Python 1.6?

Python 1.6 можно считать релизом Python «Договорные обязательства». После того, как основная команда разработчиков покинула CNRI в мае 2000 года, CNRI попросила создать релиз 1.6, содержащий все наработки по Python, которые были сделаны в CNRI. Таким образом, Python 1.6 представляет собой состояние дерева CVS на май 2000 года, а наиболее значительной новой возможностью является поддержка Юникода. Разумеется, разработка продолжалась и после мая, поэтому дерево 1.6 получило несколько исправлений, чтобы обеспечить совместимость с Python 2.0. Таким образом, 1.6 - это часть эволюции Python, а не побочная ветвь.

Так стоит ли вам интересоваться Python 1.6? Скорее всего, нет. Релизы 1.6final и 2.0beta1 были выпущены в один и тот же день (5 сентября 2000 года), и планируется завершить работу над Python 2.0 в течение месяца или около того. Если у вас есть приложения, которые нужно поддерживать, то нет смысла ломать их, переходя на 1.6, исправлять их, а затем через месяц снова ломать, переходя на 2.0; лучше сразу перейти на 2.0. Большинство действительно интересных функций, описанных в этом документе, есть только в 2.0, потому что большая часть работы была проделана в период с мая по сентябрь.

Новый процесс разработки

Самое важное изменение в Python 2.0, возможно, заключается не в коде, а в том, как разрабатывается Python: в мае 2000 года разработчики Python начали использовать инструменты SourceForge для хранения исходного кода, отслеживания сообщений об ошибках и управления очередью патчей. Чтобы сообщить об ошибках или отправить исправления для Python 2.0, используйте инструменты отслеживания ошибок и управления исправлениями, доступные на странице проекта Python, расположенной по адресу https://sourceforge.net/projects/python/.

Наиболее важным из сервисов, размещенных на SourceForge, является дерево Python CVS - хранилище с контролем версий, содержащее исходный код Python. Раньше доступ к дереву CVS на запись имели примерно 7 или около того человек, и все патчи должны были быть проверены и зарегистрированы одним из людей в этом коротком списке. Очевидно, что это было не очень удобно для масштабирования. Переместив дерево CVS на SourceForge, стало возможным предоставлять доступ на запись большему количеству людей; по состоянию на сентябрь 2000 года доступ к проверке изменений имели 27 человек, что в четыре раза больше. Это сделало возможными масштабные изменения, которые не были бы предприняты, если бы их пришлось процеживать через небольшую группу основных разработчиков. Например, однажды Питер Шнайдер-Камп решил отказаться от совместимости с K&R C и перевести исходный код Python на ANSI C. Получив одобрение в списке рассылки python-dev, он начал шквал проверок, который продолжался около недели, другие разработчики присоединились, чтобы помочь, и дело было сделано. Если бы доступ на запись имели только 5 человек, возможно, эта задача рассматривалась бы как «хорошая, но не стоящая времени и усилий», и она никогда бы не была выполнена.

Переход на использование сервисов SourceForge привел к значительному увеличению скорости разработки. Патчи теперь отправляются, комментируются, пересматриваются людьми, отличными от первоначального автора, и переходят от одного человека к другому, пока патч не будет признан достойным проверки. Баги отслеживаются в одном центральном месте и могут быть назначены определенным человеком для исправления, а мы можем подсчитать количество открытых ошибок, чтобы оценить прогресс. Это не обошлось без издержек: разработчикам теперь приходится иметь дело с большим количеством электронной почты, следить за списками рассылки, а для новой среды пришлось написать специальные инструменты. Например, SourceForge по умолчанию отправляет по электронной почте сообщения о патчах и ошибках, которые совершенно бесполезны, поэтому Ка-Пинг Йи написал HTML-скраппер, который отправляет более полезные сообщения.

Простота добавления кода привела к некоторым первоначальным трудностям, например, к тому, что код регистрировался до того, как был готов, или без четкого согласия группы разработчиков. Возникший процесс утверждения в некоторой степени похож на тот, что используется группой Apache. Разработчики могут проголосовать за патч +1, +0, -0 или -1; +1 и -1 означают принятие или отклонение, а +0 и -0 означают, что разработчику в основном безразлично изменение, хотя и с небольшим положительным или отрицательным уклоном. Наиболее существенным изменением по сравнению с моделью Apache является то, что голосование по сути носит рекомендательный характер, позволяя Гвидо ван Россуму, обладающему статусом пожизненного диктатора, знать общее мнение. Он по-прежнему может игнорировать результаты голосования и одобрять или отклонять изменения, даже если сообщество с ним не согласно.

Создание фактического патча - это последний шаг в добавлении новой функции, и он обычно проще, чем предыдущая задача по разработке хорошего дизайна. Обсуждение новых возможностей часто может вылиться в длинные ветки списков рассылки, что затрудняет слежение за дискуссией, и никто не может читать все сообщения в python-dev. Поэтому был создан относительно формальный процесс написания предложений по улучшению Python (PEPs), по образцу процесса RFC в интернете. PEP - это проект документа, в котором описывается предлагаемая новая функция, и он постоянно пересматривается до тех пор, пока сообщество не придет к консенсусу, либо приняв, либо отклонив предложение. Цитата из введения к PEP 1, «Цель и руководство PEP»:

PEP расшифровывается как Python Enhancement Proposal. PEP - это проектный документ, предоставляющий информацию сообществу Python или описывающий новую функцию для Python. PEP должен содержать краткую техническую спецификацию функции и ее обоснование.

Мы планируем, что PEP станут основными механизмами для предложения новых возможностей, сбора мнений сообщества по тому или иному вопросу и документирования проектных решений, которые были приняты в Python. Автор PEP отвечает за достижение консенсуса в сообществе и документирование особых мнений.

Читайте остальную часть PEP 1, чтобы узнать подробности процесса редактирования, стиля и формата PEP. PEP хранятся в CVS-дереве Python на SourceForge, хотя и не являются частью дистрибутива Python 2.0, а также доступны в HTML-формате на сайте https://peps.python.org/. По состоянию на сентябрь 2000 года существует 25 PEP, начиная с PEP 201, «Lockstep Iteration», и заканчивая PEP 225, «Elementwise/Objectwise Operators».

Юникод

Самое большое нововведение в Python 2.0 - это новый фундаментальный тип данных: строки Unicode. Unicode использует 16-битные числа для представления символов вместо 8-битных чисел, используемых ASCII, что означает, что можно поддерживать 65 536 различных символов.

Окончательный вариант интерфейса для поддержки Unicode был разработан в ходе бесчисленных и часто штормовых обсуждений в списке рассылки python-dev и в основном реализован Марком-Андре Лембургом на основе реализации строкового типа Unicode Фредрика Лунда. Подробное объяснение интерфейса было написано в PEP 100, «Интеграция Python Unicode». В этой статье мы просто рассмотрим наиболее важные моменты, связанные с интерфейсами Unicode.

В исходном коде Python строки Юникода записываются как u"string". Произвольные символы Юникода могут быть записаны с помощью новой управляющей последовательности \uHHHH, где HHH - это четырехзначное шестнадцатеричное число от 0000 до FFFF. Также можно использовать существующую последовательность \xHH, а для символов до U+01FF, которые обозначаются \777, можно использовать восьмеричную эскейп-последовательность.

Строки Юникода, как и обычные строки, представляют собой неизменяемый тип последовательности. Их можно индексировать и нарезать, но нельзя изменять на месте. У строк Юникода есть метод encode( [encoding] ), который возвращает 8-битную строку в нужной кодировке. Кодировки именуются строками, такими как 'ascii', 'utf-8', 'iso-8859-1' или любыми другими. Определен API кодека для реализации и регистрации новых кодировок, которые затем доступны во всех программах на Python. Если кодировка не указана, по умолчанию обычно используется 7-битная кодировка ASCII, хотя ее можно изменить для вашей установки Python, вызвав функцию sys.setdefaultencoding(encoding) в адаптированной версии site.py.

Объединение 8-битных и юникодных строк всегда приводит к юникоду, используя кодировку ASCII по умолчанию; результатом 'a' + u'bc' будет u'abc'.

Были добавлены новые встроенные функции и изменены существующие встроенные функции для поддержки Unicode:

  • unichr(ch) возвращает строку Юникода длиной 1 символ, содержащую символ ch.

  • ord(u), где u - 1-символьная обычная строка или строка Unicode, возвращает номер символа в виде целого числа.

  • unicode(string [, encoding]  [, errors] ) создает строку Unicode из 8-битной строки. encoding - это строка с именем используемой кодировки. Параметр errors определяет, как поступать с символами, недопустимыми для текущей кодировки; передача значения 'strict' приводит к возникновению исключения при любой ошибке кодировки, в то время как 'ignore' заставляет игнорировать ошибки, а 'replace' использует U+FFFD, официальный символ замены, в случае возникновения каких-либо проблем.

  • Оператор exec и различные встроенные функции, такие как eval(), getattr() и setattr(), также будут принимать строки Unicode и обычные строки. (Возможно, в процессе исправления этой ошибки были упущены некоторые встроенные функции; если вы обнаружите встроенную функцию, которая принимает строки, но не принимает строки Юникода, пожалуйста, сообщите об этом как об ошибке).

Новый модуль unicodedata предоставляет интерфейс для работы со свойствами символов Unicode. Например, unicodedata.category(u'A') возвращает двухсимвольную строку „Lu“, причем „L“ означает, что это буква, а „u“ - что она прописная. unicodedata.bidirectional(u'\u0660') возвращает „AN“, что означает, что U+0660 - это арабское число.

Модуль codecs содержит функции для поиска существующих и регистрации новых кодировок. Если вы не хотите реализовать новую кодировку, чаще всего вы будете использовать функцию codecs.lookup(encoding), которая возвращает кортеж из 4 элементов: (encode_func, decode_func, stream_reader, stream_writer).

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

  • decode_func является противоположностью encode_func, принимая 8-битную строку и возвращая 2-кортеж (ustring, length), состоящий из результирующей Unicode-строки ustring и целого числа length, указывающего, сколько 8-битной строки было использовано.

  • stream_reader - это класс, поддерживающий декодирование входных данных из потока. stream_reader(file_obj) возвращает объект, поддерживающий методы read(), readline() и readlines(). Все эти методы переводят из заданной кодировки и возвращают строки Unicode.

  • stream_writer, аналогично, является классом, поддерживающим кодирование вывода в поток. stream_writer(file_obj) возвращает объект, поддерживающий методы write() и writelines(). Эти методы принимают строки Unicode, переводя их в заданную кодировку на выходе.

Например, следующий код записывает строку Unicode в файл, кодируя ее как UTF-8:

import codecs

unistr = u'\u0660\u2000ab ...'

(UTF8_encode, UTF8_decode,
 UTF8_streamreader, UTF8_streamwriter) = codecs.lookup('UTF-8')

output = UTF8_streamwriter( open( '/tmp/output', 'wb') )
output.write( unistr )
output.close()

Следующий код будет читать UTF-8 из файла:

input = UTF8_streamreader( open( '/tmp/output', 'rb') )
print repr(input.read())
input.close()

Регулярные выражения с поддержкой Юникода доступны через модуль re, который имеет новую базовую реализацию под названием SRE, написанную Фредриком Лундом из Secret Labs AB.

Добавлена опция командной строки -U, которая заставляет компилятор Python интерпретировать все строковые литералы как строковые литералы Unicode. Эта опция предназначена для тестирования и защиты вашего кода Python на будущее, так как некоторые будущие версии Python могут отказаться от поддержки 8-битных строк и предоставлять только строки Юникода.

Составление списков

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

Существующие функции map() и filter() можно использовать для этой цели, но они требуют наличия функции в качестве одного из аргументов. Это хорошо, если есть встроенная функция, которую можно передать напрямую, но если ее нет, вам придется создать маленькую функцию для выполнения требуемой работы, а правила скопинга Python делают результат некрасивым, если маленькой функции нужна дополнительная информация. Возьмем первый пример из предыдущего абзаца - поиск всех строк в списке, содержащих заданную подстроку. Для этого можно написать следующее:

# Given the list L, make a list of all strings
# containing the substring S.
sublist = filter( lambda s, substring=S:
                     string.find(s, substring) != -1,
                  L)

Из-за правил скопирования в Python используется аргумент по умолчанию, чтобы анонимная функция, созданная выражением lambda, знала, какая подстрока ищется. Понимание списков делает это чище:

sublist = [ s for s in L if string.find(s, S) != -1 ]

Списки имеют вид:

[ expression for expr in sequence1
             for expr2 in sequence2 ...
             for exprN in sequenceN
             if condition ]

Клаузы forin содержат последовательности, по которым будет производиться итерация. Последовательности не обязательно должны быть одинаковой длины, потому что они итерируются не параллельно, а слева направо; более подробно это объясняется в следующих параграфах. Элементами сгенерированного списка будут последовательные значения выражения. Заключительное предложение if является необязательным; если оно присутствует, то выражение будет оценено и добавлено к результату только в том случае, если условие истинно.

Чтобы сделать семантику очень понятной, понимание списка эквивалентно следующему коду Python:

for expr1 in sequence1:
    for expr2 in sequence2:
    ...
        for exprN in sequenceN:
             if (condition):
                  # Append the value of
                  # the expression to the
                  # resulting list.

Это означает, что при наличии нескольких forin клаузул результирующий список будет равен произведению длин всех последовательностей. Если у вас есть два списка длины 3, то выходной список будет состоять из 9 элементов:

seq1 = 'abc'
seq2 = (1,2,3)
>>> [ (x,y) for x in seq1 for y in seq2]
[('a', 1), ('a', 2), ('a', 3), ('b', 1), ('b', 2), ('b', 3), ('c', 1),
('c', 2), ('c', 3)]

Чтобы не вносить двусмысленность в грамматику Python, если выражение создает кортеж, оно должно быть окружено круглыми скобками. Первый список, приведенный ниже, является синтаксической ошибкой, а второй - правильным:

# Syntax error
[ x,y for x in seq1 for y in seq2]
# Correct
[ (x,y) for x in seq1 for y in seq2]

Идея понимания списков изначально пришла из функционального языка программирования Haskell (https://www.haskell.org). Грег Юинг наиболее эффективно аргументировал необходимость их добавления в Python и написал первоначальный патч для понимания списков, который затем, казалось, бесконечно долго обсуждался в списке рассылки python-dev и поддерживался в актуальном состоянии Скипом Монтанаро.

Дополненное задание

В Python 2.0 были добавлены дополненные операторы присваивания - еще одна давно востребованная функция. К дополненным операторам присваивания относятся +=, -=, *= и так далее. Например, оператор a += 2 увеличивает значение переменной a на 2, что эквивалентно более длинному оператору a = a + 2.

Полный список поддерживаемых операторов присваивания: +=, -=, *=, /=, %=, **=, &=, |=, ^=, >>= и <<=. Классы Python могут переопределять дополненные операторы присваивания, определяя методы с именами __iadd__(), __isub__() и т. д. Например, следующий класс Number хранит число и поддерживает использование += для создания нового экземпляра с увеличенным значением.

class Number:
    def __init__(self, value):
        self.value = value
    def __iadd__(self, increment):
        return Number( self.value + increment)

n = Number(5)
n += 3
print n.value

Специальный метод __iadd__() вызывается со значением инкремента и должен вернуть новый экземпляр с соответствующим измененным значением; это возвращаемое значение привязывается как новое значение переменной в левой части.

Операторы дополненного присваивания впервые появились в языке программирования C, и большинство производных от C языков, таких как awk, C++, Java, Perl и PHP, также поддерживают их. Патч дополненного присваивания был реализован Томасом Воутерсом.

Строковые методы

До сих пор функции манипулирования строками находились в модуле string, который обычно являлся внешним интерфейсом для модуля strop, написанного на C. Добавление Unicode создало трудности для модуля strop, поскольку все функции нужно было переписать, чтобы они могли принимать либо 8-битные, либо Unicode-строки. Для таких функций, как string.replace(), которая принимает 3 строковых аргумента, это означает восемь возможных перестановок и соответственно сложный код.

Вместо этого Python 2.0 перекладывает проблему на тип string, делая функции манипулирования строками доступными через методы как для 8-битных строк, так и для строк Unicode.

>>> 'andrew'.capitalize()
'Andrew'
>>> 'hostname'.replace('os', 'linux')
'hlinuxtname'
>>> 'moshe'.find('sh')
2

Одна вещь, которая не изменилась, несмотря на примечательную шутку April Fools, заключается в том, что строки в Python неизменяемы. Таким образом, строковые методы возвращают новые строки и не изменяют строку, над которой они работают.

Старый модуль string все еще существует для обратной совместимости, но в основном он выступает в качестве внешнего интерфейса для новых строковых методов.

Два метода, которые не имеют параллелей в версиях до 2.0, хотя и существовали в JPython довольно долгое время, - это startswith() и endswith(). s.startswith(t) эквивалентен s[:len(t)] == t, а s.endswith(t) эквивалентен s[-len(t):] == t.

Еще один метод, заслуживающий особого упоминания, - join(). Метод join() принимает один параметр - последовательность строк - и эквивалентен функции string.join() из старого модуля string, только аргументы поменяны местами. Другими словами, s.join(seq) эквивалентен старому string.join(seq, s).

Сборка мусора из циклов

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

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

Рассмотрим простейший цикл - экземпляр класса, который имеет ссылку на самого себя:

instance = SomeClass()
instance.myself = instance

После выполнения двух приведенных выше строк кода количество ссылок на instance равно 2; одна из них относится к переменной с именем 'instance', а другая - к атрибуту myself экземпляра.

Если следующей строкой кода будет del instance, что произойдет? Количество ссылок на instance уменьшается на 1, так что его количество ссылок равно 1; ссылка в атрибуте myself по-прежнему существует. Однако этот экземпляр больше не доступен через код Python, и его можно удалить. Несколько объектов могут участвовать в цикле, если они имеют ссылки друг на друга, что приводит к утечке всех объектов.

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

Запуск алгоритма обнаружения циклов занимает некоторое время, что приводит к дополнительным накладным расходам. Есть надежда, что после того, как мы приобретем опыт работы со сбором циклов в версии 2.0, в Python 2.1 можно будет минимизировать эти накладные расходы с помощью тщательной настройки. Пока неясно, насколько снизится производительность, поскольку бенчмаркинг - дело непростое и в значительной степени зависит от того, как часто программа создает и уничтожает объекты. Обнаружение циклов можно отключить при компиляции Python, если вы не можете позволить себе даже крошечный штраф за скорость или подозреваете, что сбор циклов глючит, указав переключатель --without-cycle-gc при запуске скрипта configure.

Несколько человек занялись этой проблемой и внесли свой вклад в ее решение. Ранняя реализация подхода к обнаружению циклов была написана Тоби Келси. Текущий алгоритм был предложен Эриком Тидеманном во время визита в CNRI, а Гвидо ван Россум и Нил Шеменауэр написали две разные реализации, которые позже были интегрированы Нилом. Многие другие люди вносили свои предложения на этом пути; архивы списка рассылки python-dev за март 2000 года содержат большую часть соответствующих обсуждений, особенно в темах «Коллекция эталонных циклов для Python» и «Снова доработка».

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

В синтаксис и встроенные функции Python были внесены различные незначительные изменения. Ни одно из изменений не имеет большого значения, но это удобные удобства.

Незначительные изменения языка

Новый синтаксис делает более удобным вызов заданной функции с кортежем аргументов и/или словарем ключевых слов-аргументов. В Python 1.5 и более ранних версиях вы использовали встроенную функцию apply(): apply(f, args, kw) вызывает функцию f() с кортежем аргументов args и аргументами в виде ключевых слов из словаря kw. apply() - то же самое в версии 2.0, но благодаря патчу от Грега Юинга f(*args, **kw) - более короткий и понятный способ добиться того же эффекта. Этот синтаксис симметричен синтаксису определения функций:

def f(*args, **kw):
    # args is a tuple of positional args,
    # kw is a dictionary of keyword args
    ...

Оператор print теперь может быть направлен в файлоподобный объект, если после оператора print добавить >> file, подобно оператору перенаправления в оболочках Unix. Раньше приходилось либо использовать метод write() файлоподобного объекта, которому не хватает удобства и простоты print, либо присваивать новое значение sys.stdout, а затем восстанавливать старое. Для отправки вывода в стандартную ошибку гораздо проще написать так:

print >> sys.stderr, "Warning: action field not supplied"

Модули теперь можно переименовывать при их импорте, используя синтаксис import module as name или from module import name as othername. Патч прислал Томас Воутерс.

Новый стиль формата доступен при использовании оператора %; „%r“ будет вставлять repr() своего аргумента. Он также был добавлен из соображений симметрии, на этот раз для симметрии с существующим стилем формата „%s“, который вставляет str() своего аргумента. Например, '%r %s' % ('abc', 'abc') возвращает строку, содержащую 'abc' abc.

Ранее не было возможности реализовать класс, который бы отменял встроенный в Python оператор in и реализовывал бы собственную версию. obj in seq возвращает true, если obj присутствует в последовательности seq; Python вычисляет это, просто перебирая все индексы последовательности, пока либо не будет найден obj, либо не будет встречен IndexError. Моше Задка внес исправление, которое добавляет магический метод __contains__() для создания собственной реализации in. Кроме того, новые встроенные объекты, написанные на C, могут определять, что для них означает in, через новый слот в протоколе последовательности.

В ранних версиях Python использовался рекурсивный алгоритм удаления объектов. Глубоко вложенные структуры данных могли привести к заполнению стека C и аварийному завершению работы интерпретатора; Кристиан Тисмер переписал логику удаления, чтобы устранить эту проблему. В связи с этим сравнение рекурсивных объектов бесконечно повторялось и приводило к сбою; Джереми Хилтон переписал код, чтобы он больше не приводил к сбою, а выдавал полезный результат. Например, после этого кода:

a = []
b = []
a.append(a)
b.append(b)

Сравнение a==b возвращает true, поскольку две рекурсивные структуры данных изоморфны. См. ветку «trashcan and PR#7» в архиве списка рассылки python-dev за апрель 2000 года, где вы найдете обсуждение, приведшее к этой реализации, а также несколько полезных ссылок. Обратите внимание, что сравнения теперь также могут вызывать исключения. В ранних версиях Python операция сравнения, такая как cmp(a,b), всегда выдавала ответ, даже если пользовательский метод __cmp__() сталкивался с ошибкой, поскольку возникающее исключение просто молча проглатывалось.

Работа по переносу Python на 64-битную Windows на процессоре Itanium была проделана, в основном Трентом Миком из ActiveState. (Смущает то, что sys.platform все еще является 'win32' на Win64, потому что, похоже, для удобства переноса MS Visual C++ рассматривает код как 32-битный на Itanium). PythonWin также поддерживает Windows CE; более подробную информацию можно найти на странице Python CE на https://pythonce.sourceforge.net/.

Еще одна новая платформа - Darwin/MacOS X; ее начальная поддержка есть в Python 2.0. Динамическая загрузка работает, если вы укажете «configure –with-dyld –with-suffix=.x». За более подробными инструкциями обратитесь к README в дистрибутиве исходного кода Python.

Была предпринята попытка облегчить один из недостатков Python - часто вызывающее недоумение исключение NameError, когда код обращается к локальной переменной до того, как ей было присвоено значение. Например, следующий код вызывает исключение на операторе print как в 1.5.2, так и в 2.0; в 1.5.2 вызывается исключение NameError, а в 2.0 - новое исключение UnboundLocalError. UnboundLocalError является подклассом NameError, поэтому любой существующий код, который ожидает, что будет поднят NameError, должен работать.

def f():
    print "i=",i
    i = i + 1
f()

Появились два новых исключения, TabError и IndentationError. Оба они являются подклассами SyntaxError и вызываются, когда код Python оказывается неправильно отступом.

Изменения во встроенных функциях

Добавлена новая встроенная функция zip(seq1, seq2, ...). zip() возвращает список кортежей, в котором каждый кортеж содержит i-й элемент из каждой последовательности аргументов. Разница между zip() и map(None, seq1, seq2) заключается в том, что map() выравнивает последовательности с помощью None, если последовательности не все одинаковой длины, а zip() усекает возвращаемый список до длины самой короткой последовательности аргументов.

Функции int() и long() теперь принимают необязательный параметр «base», когда первым аргументом является строка. int('123', 10) возвращает 123, а int('123', 16) - 291. int(123, 16) вызывает исключение TypeError с сообщением «не удается преобразовать нестроку с явным base».

В модуль sys добавлена новая переменная, содержащая более подробную информацию о версии. sys.version_info - это кортеж (major, minor, micro, level, serial). Например, в гипотетической версии 2.0.1beta1, sys.version_info будет (2, 0, 1, 'beta', 1). level - это строка, например "alpha", "beta" или "final" для финального релиза.

В словарях появился странный новый метод setdefault(key, default), который ведет себя аналогично существующему методу get(). Однако если ключ отсутствует, setdefault() возвращает значение default, как это делает get(), а также вставляет его в словарь в качестве значения для key. Таким образом, следующие строки кода:

if dict.has_key( key ): return dict[key]
else:
    dict[key] = []
    return dict[key]

может быть сведена к единственному выражению return dict.setdefault(key, []).

Интерпретатор устанавливает максимальную глубину рекурсии, чтобы отловить убегающую рекурсию до того, как она заполнит стек C и вызовет дамп ядра или GPF. Раньше это ограничение фиксировалось при компиляции Python, но в 2.0 максимальная глубина рекурсии может быть прочитана и изменена с помощью sys.getrecursionlimit() и sys.setrecursionlimit(). Значение по умолчанию равно 1000, а приблизительное максимальное значение для конкретной платформы можно узнать, запустив новый скрипт Misc/find_recursionlimit.py.

Переход на версию 2.0

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

Изменение, которое, вероятно, сломает больше всего кода, - это ужесточение аргументов, принимаемых некоторыми методами. Некоторые методы принимают несколько аргументов и рассматривают их как кортеж, в частности различные списочные методы, такие как append() и insert(). В ранних версиях Python, если L является списком, L.append( 1,2 ) добавляет к нему кортеж (1,2). В Python 2.0 это приводит к возникновению исключения TypeError с сообщением: „append требует ровно 1 аргумент; дано 2“. Исправление заключается в том, чтобы просто добавить дополнительный набор круглых скобок, чтобы передать оба значения в виде кортежа: L.append( (1,2) ).

Ранние версии этих методов были более щадящими, поскольку для разбора аргументов использовалась старая функция интерфейса Python на языке C; в версии 2.0 они модернизированы и теперь используют PyArg_ParseTuple(), текущую функцию разбора аргументов, которая выдает более полезные сообщения об ошибках и рассматривает многоаргументные вызовы как ошибки. Если вам совершенно необходимо использовать 2.0, но вы не можете исправить свой код, вы можете отредактировать Objects/listobject.c и определить символ препроцессора NO_STRICT_LIST_APPEND, чтобы сохранить старое поведение; но это не рекомендуется.

Некоторые функции в модуле socket в этом смысле все же более щадящие. Например, socket.connect( ('hostname', 25) ) - это правильная форма, передающая кортеж, представляющий IP-адрес, но socket.connect('hostname', 25) тоже работает. socket.connect_ex и socket.bind также не вызывают затруднений. В версии 2.0alpha1 эти функции были ужесточены, но поскольку в документации фактически использовалась ошибочная форма с несколькими аргументами, многие люди писали код, который ломался при более строгой проверке. GvR отказалась от изменений перед лицом реакции общественности, поэтому для модуля socket документация была исправлена, а форма множественного аргумента просто помечена как устаревшая; она будет снова ужесточена в будущей версии Python.

Эскейп \x в строковых литералах теперь принимает ровно 2 шестнадцатеричные цифры. Раньше она использовала все шестнадцатеричные цифры, следующие за „x“, и брала младшие 8 бит результата, так что \x123456 была эквивалентна \x56.

Исключения AttributeError и NameError получили более дружелюбное сообщение об ошибке, текст которого будет выглядеть примерно так: 'Spam' instance has no attribute 'eggs' или name 'eggs' is not defined. Ранее сообщением об ошибке было просто отсутствующее имя атрибута eggs, и код, написанный с целью воспользоваться этим фактом, в 2.0 будет ломаться.

Была проделана определенная работа, чтобы сделать целые и длинные числа более взаимозаменяемыми. В 1.5.2 для Solaris была добавлена поддержка больших файлов, позволяющая читать файлы размером более 2 Гб; это заставило метод tell() файловых объектов возвращать длинное целое число вместо обычного целого числа. Некоторые программы вычитали два смещения файлов и пытались использовать результат для умножения последовательности или разрезания строки, но это вызывало ошибку TypeError. В версии 2.0 длинные целые числа можно использовать для умножения или разрезания последовательности, и они будут вести себя так, как вы интуитивно ожидаете; 3L * 'abc' дает „abcabcabc“, а (0,1,2,3)[2L:4L] дает (2,3). Длинные целые числа также могут использоваться в различных контекстах, где раньше принимались только целые числа, например, в методе seek() для файловых объектов и в форматах, поддерживаемых оператором % (%d, %i, %x и т. д.). Например, оператор "%d" % 2L**64 выдает строку 18446744073709551616.

Самое тонкое изменение в длинных целых числах заключается в том, что в str() длинного целого числа больше нет символа „L“, хотя в repr() он по-прежнему присутствует. Символ „L“ раздражал многих людей, которые хотели печатать длинные целые числа, выглядящие как обычные целые числа, поскольку им приходилось из кожи вон лезть, чтобы отрезать этот символ. В версии 2.0 такой проблемы больше нет, но код, выполняющий str(longval)[:-1] и предполагающий наличие „L“, теперь будет терять последнюю цифру.

При взятии repr() из float теперь используется другая точность форматирования, чем при взятии str(). repr() использует строку формата %.17g для sprintf() языка C, а str() использует %.12g, как и раньше. В результате для некоторых чисел repr() может иногда показывать больше десятичных знаков, чем str(). Например, число 8.1 не может быть точно представлено в двоичном виде, поэтому repr(8.1) - это '8.0999999999999996', а str(8.1) - это '8.1'.

Опция командной строки -X, которая превращала все стандартные исключения в строки, а не в классы, была удалена; теперь стандартные исключения всегда будут классами. Модуль exceptions, содержащий стандартные исключения, был переведен с Python на встроенный модуль C, написанный Барри Варшавой и Фредриком Лундом.

Расширение/присоединение Изменения

Некоторые изменения скрыты от глаз и будут заметны только тем, кто пишет модули расширения на C или встраивает интерпретатор Python в более крупное приложение. Если вы не имеете дела с C API Python, можете смело пропустить этот раздел.

Номер версии Python C API был увеличен, поэтому расширения на C, скомпилированные для 1.5.2, должны быть перекомпилированы, чтобы работать с 2.0. В Windows Python 2.0 не может импортировать стороннее расширение, созданное для Python 1.5.x, из-за того, как работают библиотеки Windows DLL, поэтому Python вызовет исключение, и импорт не будет выполнен.

Пользователи модуля ExtensionClass Джима Фултона будут рады узнать, что были добавлены крючки, благодаря которым ExtensionClasses теперь поддерживают isinstance() и issubclass(). Это означает, что вам больше не нужно помнить о написании кода типа if type(obj) == myExtensionClass, а можно использовать более естественный if isinstance(obj, myExtensionClass).

Файл Python/importdl.c, который представлял собой массу #ifdef для поддержки динамической загрузки на разных платформах, был очищен и реорганизован Грегом Стейном. importdl.c стал совсем маленьким, а код, специфичный для конкретной платформы, был перемещен в кучу файлов Python/dynload_*.c. Еще одна чистка: в каталоге Include/ было несколько файлов my*.h, содержащих различные хаки для переносимости; они были объединены в один файл, Include/pyport.h.

Завершена долгожданная перестройка malloc Владимира Марангозова, позволяющая упростить использование интерпретатором Python пользовательского аллокатора вместо стандартного malloc() на Си. Для ознакомления с документацией читайте комментарии в Include/pymem.h и Include/objimpl.h. Длительные обсуждения, в ходе которых был разработан интерфейс, можно найти в веб-архивах списков „patches“ и „python-dev“ на python.org.

Последние версии среды разработки GUSI для MacOS поддерживают потоки POSIX. Поэтому поддержка потоков POSIX в Python теперь работает на Macintosh. Также была внесена поддержка потоков с помощью пользовательской библиотеки GNU pth.

Поддержка потоков в Windows также была улучшена. Windows поддерживает блокировки потоков, которые используют объекты ядра только в случае споров; в обычном случае, когда споров нет, они используют более простые функции, которые на порядок быстрее. Потоковая версия Python 1.5.2 на NT работает вдвое медленнее, чем непотоковая; с изменениями в версии 2.0 разница составляет всего 10 %. Эти улучшения были внесены Яковом Марковичем.

В исходном тексте Python 2.0 теперь используются только прототипы ANSI C, поэтому для компиляции Python теперь требуется компилятор ANSI C, а компилятор, поддерживающий только K&R C, больше не может быть использован.

Ранее виртуальная машина Python использовала 16-битные числа в своем байткоде, что ограничивало размер исходных файлов. В частности, это влияло на максимальный размер литеральных списков и словарей в исходниках Python; иногда люди, генерирующие код Python, сталкивались с этим ограничением. Заплатка Чарльза Г. Уолдмана увеличивает ограничение с 2**16 до 2**32.

Добавлены три новые удобные функции, предназначенные для добавления констант в словарь модуля при его инициализации: PyModule_AddObject(), PyModule_AddIntConstant() и PyModule_AddStringConstant(). Каждая из этих функций принимает объект модуля, нуль-терминированную C-строку, содержащую имя, которое нужно добавить, и третий аргумент для значения, которое будет присвоено этому имени. Третий аргумент - это, соответственно, объект Python, C long или C string.

Добавлен API-обертка для обработчиков сигналов в стиле Unix. PyOS_getsig() получает обработчик сигнала, а PyOS_setsig() устанавливает новый обработчик.

Distutils: Упрощение установки модулей

До Python 2.0 установка модулей была утомительным занятием - не было способа автоматически определить, где установлен Python, или какие опции компилятора использовать для модулей расширения. Авторам программ приходилось проходить через сложный ритуал редактирования Makefiles и конфигурационных файлов, которые действительно работают только на Unix и не поддерживают Windows и MacOS. Пользователи Python сталкивались с дико отличающимися инструкциями по установке, которые варьировались в разных пакетах расширений, что превращало администрирование установки Python в рутину.

Группа SIG по дистрибутивным утилитам, возглавляемая Грегом Уордом, создала Distutils - систему, значительно упрощающую установку пакетов. Они формируют пакет distutils, новую часть стандартной библиотеки Python. В лучшем случае установка модуля Python из исходников потребует тех же действий: сначала нужно просто распаковать tarball или zip-архив, а затем запустить «python setup.py install». Платформа будет определена автоматически, компилятор распознан, модули расширения C будут скомпилированы, а дистрибутив установлен в нужную директорию. Дополнительные аргументы командной строки обеспечивают больший контроль над процессом установки, а пакет distutils предлагает множество возможностей для отмены настроек по умолчанию - разделение сборки и установки, сборка или установка в каталоги не по умолчанию и многое другое.

Для того чтобы использовать Distutils, вам нужно написать setup.py скрипт. Для простого случая, когда программа содержит только файлы .py, минимальный setup.py может состоять всего из нескольких строк:

from distutils.core import setup
setup (name = "foo", version = "1.0",
       py_modules = ["module1", "module2"])

Файл setup.py не намного сложнее, если программное обеспечение состоит из нескольких пакетов:

from distutils.core import setup
setup (name = "foo", version = "1.0",
       packages = ["package", "package.subpackage"])

Расширение на C может быть самым сложным случаем; вот пример, взятый из пакета PyXML:

from distutils.core import setup, Extension

expat_extension = Extension('xml.parsers.pyexpat',
     define_macros = [('XML_NS', None)],
     include_dirs = [ 'extensions/expat/xmltok',
                      'extensions/expat/xmlparse' ],
     sources = [ 'extensions/pyexpat.c',
                 'extensions/expat/xmltok/xmltok.c',
                 'extensions/expat/xmltok/xmlrole.c', ]
       )
setup (name = "PyXML", version = "0.5.4",
       ext_modules =[ expat_extension ] )

Distutils также может позаботиться о создании исходных и бинарных дистрибутивов. Команда «sdist», выполняемая командой «python setup.py sdist», создает исходный дистрибутив, например foo-1.0.tar.gz. Добавление новых команд не представляет сложности: уже были добавлены команды «bdist_rpm» и «bdist_wininst» для создания RPM-дистрибутива и установщика Windows для программного обеспечения, соответственно. Команды для создания других форматов дистрибутивов, таких как пакеты Debian и файлы Solaris .pkg, находятся на разных стадиях разработки.

Все это описано в новом руководстве Распространение модулей Python, которое присоединяется к основному набору документации по Python.

Модули XML

В состав Python 1.5.2 входил простой парсер XML в виде модуля xmllib, созданного Сьёрдом Мюллендером. После выхода 1.5.2 стали распространены два различных интерфейса для обработки XML: SAX2 (вторая версия Simple API for XML) предоставляет интерфейс, управляемый событиями и имеющий некоторое сходство с xmllib, а DOM (Document Object Model) предоставляет древовидный интерфейс, преобразующий XML-документ в дерево узлов, которые можно обходить и изменять. Python 2.0 включает в себя интерфейс SAX2 и урезанный интерфейс DOM в составе пакета xml. Здесь мы дадим краткий обзор этих новых интерфейсов; за полной информацией обращайтесь к документации по Python или исходному коду. Python XML SIG также работает над улучшением документации.

Поддержка SAX2

SAX определяет событийно-ориентированный интерфейс для разбора XML. Чтобы использовать SAX, вы должны написать класс обработчика SAX. Классы-обработчики наследуются от различных классов, предоставляемых SAX, и переопределяют различные методы, которые затем будут вызываться парсером XML. Например, методы startElement() и endElement() вызываются для каждого начального и конечного тега, встреченного парсером, метод characters() вызывается для каждого блока символьных данных и так далее.

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

Например, этот небольшой пример программы определяет обработчик, который печатает сообщение для каждого начального и конечного тега, а затем разбирает файл hamlet.xml с его помощью:

from xml import sax

class SimpleHandler(sax.ContentHandler):
    def startElement(self, name, attrs):
        print 'Start of element:', name, attrs.keys()

    def endElement(self, name):
        print 'End of element:', name

# Create a parser object
parser = sax.make_parser()

# Tell it what handler to use
handler = SimpleHandler()
parser.setContentHandler( handler )

# Parse a file!
parser.parse( 'hamlet.xml' )

Для получения дополнительной информации обратитесь к документации по Python или к XML HOWTO на сайте https://pyxml.sourceforge.net/topics/howto/xml-howto.html.

Поддержка DOM

Объектная модель документа - это древовидное представление XML-документа. Экземпляр верхнего уровня Document является корнем дерева и имеет единственного ребенка, который является экземпляром верхнего уровня Element. У этого Element есть дочерние узлы, представляющие символьные данные и любые вложенные элементы, у которых могут быть свои дочерние узлы, и так далее. Используя DOM, вы можете перемещаться по полученному дереву любым удобным способом, получать доступ к значениям элементов и атрибутов, вставлять и удалять узлы, а также преобразовывать дерево обратно в XML.

DOM полезен для модификации XML-документов, поскольку вы можете создать дерево DOM, изменить его, добавив новые узлы или перестроив поддеревья, а затем получить на выходе новый XML-документ. Вы также можете построить дерево DOM вручную и преобразовать его в XML, что может быть более гибким способом получения XML-документа, чем просто запись <tag1></tag1> в файл.

Реализация DOM, входящая в состав Python, находится в модуле xml.dom.minidom. Это облегченная реализация DOM первого уровня с поддержкой пространств имен XML. Для создания дерева DOM предусмотрены удобные функции parse() и parseString():

from xml.dom import minidom
doc = minidom.parse('hamlet.xml')

doc - это экземпляр Document. Document, как и все остальные классы DOM, такие как Element и Text, является подклассом базового класса Node. Поэтому все узлы в DOM-дереве поддерживают некоторые общие методы, такие как toxml(), который возвращает строку, содержащую XML-представление узла и его дочерних элементов. Каждый класс также имеет свои собственные специальные методы; например, экземпляры Element и Document имеют метод для поиска всех дочерних элементов с заданным именем тега. Продолжая предыдущий пример из двух строк:

perslist = doc.getElementsByTagName( 'PERSONA' )
print perslist[0].toxml()
print perslist[1].toxml()

Для XML-файла Hamlet приведенные выше строки выводят:

<PERSONA>CLAUDIUS, king of Denmark. </PERSONA>
<PERSONA>HAMLET, son to the late, and nephew to the present king.</PERSONA>

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

root = doc.documentElement

# Remove the first child
root.removeChild( root.childNodes[0] )

# Move the new first child to the end
root.appendChild( root.childNodes[0] )

# Insert the new first child (originally,
# the third child) before the 20th child.
root.insertBefore( root.childNodes[0], root.childNodes[20] )

И снова я отсылаю вас к документации Python за полным списком различных классов Node и их методов.

Отношение к PyXML

Специальная группа XML Special Interest Group уже некоторое время работает над кодом Python, связанным с XML. Дистрибутив кода под названием PyXML доступен на веб-страницах SIG по адресу https://www.python.org/community/sigs/current/xml-sig. В дистрибутиве PyXML также используется имя пакета xml. Если вы писали программы, в которых использовался PyXML, вам, вероятно, интересно, насколько он совместим с пакетом 2.0 xml.

Ответ заключается в том, что пакет xml в Python 2.0 не совместим с PyXML, но его можно сделать совместимым, установив последнюю версию PyXML. Многие приложения могут обойтись поддержкой XML, входящей в состав Python 2.0, но более сложные приложения потребуют установки полного пакета PyXML. При установке PyXML версии 0.6.0 или выше заменит пакет xml, поставляемый вместе с Python, и будет представлять собой строгий супернабор стандартного пакета, добавляющий множество дополнительных возможностей. Некоторые из дополнительных возможностей PyXML включают:

  • 4DOM, полная реализация DOM от FourThought, Inc.

  • Валидирующий парсер xmlproc, написанный Ларсом Мариусом Гаршолом.

  • Модуль ускорителя парсера sgmlop, написанный Фредриком Лундом.

Изменения в модулях

В обширную стандартную библиотеку Python было внесено множество улучшений и исправлений; некоторые из затронутых модулей включают readline, ConfigParser, cgi, calendar, posix, readline, xmllib, aifc, chunk, wave, random, shelve и nntplib. Точные сведения о каждом патче можно найти в журналах CVS.

Брайан Галлев внес вклад в поддержку OpenSSL для модуля socket. OpenSSL - это реализация Secure Socket Layer, которая шифрует данные, передаваемые через сокет. При компиляции Python вы можете изменить Modules/Setup, чтобы включить поддержку SSL, что добавляет дополнительную функцию в модуль socket: socket.ssl(socket, keyfile, certfile), которая принимает объект сокета и возвращает SSL-сокет. Модули httplib и urllib также были изменены для поддержки https:// URL, хотя никто не реализовал FTP или SMTP через SSL.

Модуль httplib был переписан Грегом Стейном для поддержки HTTP/1.1.

Обеспечена обратная совместимость с версией 1.5 httplib, хотя использование таких возможностей HTTP/1.1, как конвейеризация, потребует переписать код, чтобы использовать другой набор интерфейсов.

Модуль Tkinter теперь поддерживает Tcl/Tk версий 8.1, 8.2 или 8.3, а поддержка старых версий 7.x была прекращена. Модуль Tkinter теперь поддерживает отображение строк Unicode в виджетах Tk. Кроме того, Фредрик Лундх внес свой вклад в оптимизацию, благодаря которой операции типа create_line и create_polygon выполняются гораздо быстрее, особенно при использовании большого количества координат.

Модуль curses был значительно расширен, начиная с улучшенной версии Оливера Андрича, чтобы предоставить множество дополнительных функций из ncurses и SYSV curses, таких как цвет, поддержка альтернативного набора символов, блокноты и поддержка мыши. Это означает, что модуль больше не совместим с операционными системами, в которых используются только BSD curses, но, похоже, в настоящее время нет ни одной ОС, которая подпадала бы под эту категорию.

Как уже упоминалось в предыдущем обсуждении поддержки Unicode в 2.0, базовая реализация регулярных выражений, предоставляемых модулем re, была изменена. SRE, новый движок регулярных выражений, написанный Фредриком Лундом и частично финансируемый Hewlett Packard, поддерживает поиск как 8-битных строк, так и строк Юникода.

Новые модули

Был добавлен ряд новых модулей. Мы просто перечислим их с краткими описаниями; за подробностями о том или ином модуле обращайтесь к документации 2.0.

  • atexit: Для регистрации функций, которые будут вызываться перед выходом из интерпретатора Python. Код, который в настоящее время напрямую устанавливает sys.exitfunc, должен быть изменен, чтобы вместо этого использовать модуль atexit, импортируя atexit и вызывая atexit.register() с функцией, которая будет вызвана при выходе. (Внесено Скипом Монтанаро.)

  • codecs, encodings, unicodedata: Добавлены как часть новой поддержки Юникода.

  • filecmp: Заменяет старые модули cmp, cmpcache и dircmp, которые теперь устарели. (Внесено Гордоном Макмилланом и Моше Задкой).

  • gettext: Этот модуль обеспечивает поддержку интернационализации (I18N) и локализации (L10N) для программ на Python, предоставляя интерфейс к библиотеке каталога сообщений GNU gettext. (Интегрирован Барри Варшавой из отдельных вкладов Мартина фон Лёвиса, Питера Функа и Джеймса Хенстриджа).

  • linuxaudiodev: Поддержка устройства /dev/audio в Linux, близнец существующего модуля sunaudiodev. (Внесено Питером Бошем, исправления внесены Джереми Хилтоном).

  • mmap: Интерфейс для работы с файлами, отображенными в памяти, как в Windows, так и в Unix. Содержимое файла может быть отображено непосредственно в память, и в этот момент он ведет себя как мутабельная строка, поэтому его содержимое можно читать и изменять. Их даже можно передавать в функции, которые ожидают обычных строк, например, в модуль re. (Внесено Сэмом Рашингом, некоторые дополнения сделаны А. М. Кючлингом).

  • pyexpat: Интерфейс к XML-парсеру Expat. (Внесено Полом Прескодом).

  • robotparser: Разбирает файл robots.txt, который используется для написания веб-пауков, вежливо избегающих определенных областей веб-сайта. Парсер принимает содержимое файла robots.txt, строит из него набор правил и затем может отвечать на вопросы о возможности получения данного URL. (Внесено Скипом Монтанаро.)

  • tabnanny: Модуль/скрипт для проверки исходного кода Python на неоднозначные отступы. (Внесено Тимом Питерсом).

  • UserString: Базовый класс, полезный для создания объектов, которые ведут себя как строки.

  • webbrowser: Модуль, обеспечивающий независимый от платформы способ запуска веб-браузера по определенному URL. Для каждой платформы различные браузеры запускаются в определенном порядке. Пользователь может изменить, какой браузер будет запущен, установив переменную окружения BROWSER. (Изначально был вдохновлен патчем Эрика С. Рэймонда к urllib, который добавлял аналогичную функциональность, но окончательный вариант модуля происходит от кода, первоначально реализованного Фредом Дрейком в Tools/idle/BrowserControl.py и адаптированного Фредом для стандартной библиотеки).

  • _winreg: Интерфейс для работы с реестром Windows. _winreg - это адаптация функций, которые были частью PythonWin с 1995 года, но теперь добавлены в основной дистрибутив и улучшены для поддержки Юникода. _winreg был написан Биллом Таттом и Марком Хэммондом.

  • zipfile: Модуль для чтения и записи архивов формата ZIP. Это архивы, создаваемые PKZIP под DOS/Windows или zip под Unix, не путать с файлами gzip-формата (которые поддерживаются модулем gzip) (Внесено Джеймсом К. Алстромом).

  • imputil: Модуль, предоставляющий более простой способ написания настраиваемых хуков импорта, по сравнению с существующим модулем ihooks. (Реализован Грегом Стейном, с большим обсуждением на python-dev).

Улучшения IDLE

IDLE - это официальная кроссплатформенная IDE для Python, написанная с использованием Tkinter. В состав Python 2.0 входит IDLE 0.6, в которой добавлен ряд новых возможностей и улучшений. Вот неполный список:

  • Улучшения и оптимизация пользовательского интерфейса, особенно в области подсветки синтаксиса и автоиндексации.

  • В браузере классов теперь отображается больше информации, например, функции верхнего уровня в модуле.

  • Ширина табуляции теперь настраивается пользователем. При открытии существующего файла Python IDLE автоматически определяет соглашения об отступах и адаптирует их.

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

  • Теперь у IDLE есть командная строка, которая во многом похожа на интерпретатор Python.

  • Во многих местах были добавлены подсказки.

  • Теперь IDLE можно установить как пакет.

  • В окне редактора теперь есть строка/колонка внизу.

  • Три новые команды нажатия клавиш: Проверить модуль (Alt-F5), Импортировать модуль (F5) и Запустить скрипт (Ctrl-F5).

Удаленные и устаревшие модули

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

Ряд модулей был перемещен в подкаталог lib-old: cmp, cmpcache, dircmp, dump, find, grep, packmail, poly, util, whatsound, zmod. Если у вас есть код, который полагается на модуль, перемещенный в lib-old, вы можете просто добавить эту директорию в sys.path, чтобы вернуть их обратно, но вам рекомендуется обновить весь код, использующий эти модули.

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

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