Что нового в 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 года, а наиболее значительной новой возможностью является поддержка Unicode. Конечно, разработка продолжалась и после мая, поэтому дерево 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, является дерево CVS Python, хранилище с контролем версий, содержащее исходный код Python. Раньше было примерно 7 или около того человек, которые имели доступ на запись к CVS-дереву, и все патчи должны были быть проверены и зарегистрированы одним из людей из этого короткого списка. Очевидно, что это было не очень масштабируемо. Переместив дерево CVS на SourceForge, стало возможным предоставить доступ на запись большему количеству людей; по состоянию на сентябрь 2000 года было 27 человек, которые могли проверять изменения, что в четыре раза больше. Это сделало возможными крупномасштабные изменения, которые не были бы предприняты, если бы их пришлось процеживать через небольшую группу основных разработчиков. Например, однажды Питеру Шнайдер-Кампу пришло в голову отказаться от совместимости с K&R C и преобразовать исходный текст на языке 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://www.python.org/dev/peps/. По состоянию на сентябрь 2000 года существует 25 PEPS, начиная с 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 строки Unicode записываются как u"string". Произвольные символы Unicode могут быть записаны с помощью новой управляющей последовательности \uHHHH, где HHH - это четырехзначное шестнадцатеричное число от 0000 до FFFF. Можно также использовать существующую последовательность \xHHHH, а для символов до U+01FF, которые представлены \777, можно использовать восьмеричную последовательность.

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

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

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

  • unichr(ch) возвращает строку Unicode длиной 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 и обычные строки. (Возможно, что в процессе исправления этой ошибки некоторые встроенные функции были упущены; если вы найдете встроенную функцию, которая принимает строки, но не принимает строки 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-битную строку и возвращает кортеж (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()

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

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

Понимание списков

Списки - это рабочий тип данных в 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

Одна вещь, которая не изменилась, несмотря на примечательную первоапрельскую шутку, заключается в том, что строки в 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 на http://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 с сообщением «can’t convert non-string with explicit 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' дает „abcabcabcabc“, а (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() плавающей величины теперь использует другую точность форматирования, чем str(). repr() использует строку формата %.17g для sprintf() языка Си, в то время как 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, который представлял собой массу #ifdefs для поддержки динамической загрузки на многих различных платформах, был очищен и реорганизован Грегом Стейном. 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, или какие опции компилятора использовать для модулей расширения. Авторам программ приходилось проходить через сложный ритуал редактирования Make-файлов и конфигурационных файлов, которые действительно работают только на 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 (версия 2 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 на сайте http://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 уровня 1 с поддержкой пространств имен 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 уже некоторое время работает над связанным с XML кодом на языке Python. Ее дистрибутив кода под названием PyXML доступен на веб-страницах SIG по адресу https://www.python.org/community/sigs/current/xml-sig. В дистрибутиве PyXML также использовалось имя пакета xml. Если вы писали программы, в которых использовался PyXML, вам, вероятно, интересно узнать о его совместимости с пакетом 2.0 xml.

Ответ заключается в том, что пакет Python 2.0 xml не совместим с 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-битных строк, так и строк Unicode.

Новые модули

Был добавлен ряд новых модулей. Мы просто перечислим их с кратким описанием; за подробностями о конкретном модуле обращайтесь к документации 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 года, но теперь были добавлены в основной дистрибутив и улучшены для поддержки Unicode. _winreg был написан Биллом Таттом и Марком Хаммондом.

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

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

Улучшения IDLE

IDLE - это официальная кроссплатформенная среда разработки 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, чтобы вернуть их обратно, но вам рекомендуется обновить любой код, использующий эти модули.

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

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

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