Что нового в 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, — это 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 (PEP) был создан относительно формальный процесс, смоделированный по RFC-процессу в Интернете. PEP — это проекты документов, рассказывающих о предлагаемой новой функции, которая постоянно пересматриваются до тех пор, пока сообщество не достигнет консенсуса, либо приняв, либо отклонив предложение. Цитата из введения к PEP 1, «Цель и рекомендации PEP»:

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

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

Прочитать оставшуюся часть PEP 1, чтобы узнать подробности процесса редактирования PEP, стиля и формата. PEP хранятся в дереве Python CVS на SourceForge, хотя они не являются частью дистрибутива Python 2.0, а также доступны в виде HTML. По состоянию на сентябрь 2000 г. существует 25 PEPS, от PEP 201, «Итерация с фиксированным шагом», до PEP 225, «Элементарные/объектные операторы».

Юникод

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

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

В исходном коде Python строки Юникод записываются как u"string". Произвольные символы Юникод можно записывать с помощью новой управляющей последовательности \uHHHH, где HHHH — четырехзначное шестнадцатеричное число от 0000 до FFFF. Также можно использовать существующую escape- последовательность \xHHHH, а восьмеричные escape-последовательности можно использовать для символов до 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'.

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

  • unichr(ch) возвращает строку Юникод длиной 1 символ, содержащую символ ch.
  • ord(u), где u — это обычная 1-символьная строка или строка Юникод, возвращает количество символов в виде целого числа.
  • unicode(string [, encoding] [, errors] ) создаёт строку Юникод из 8-битной строки. encoding — это строка, обозначающая используемую кодировку. Параметр errors определяет обработку символов, недопустимых для текущей кодировки; передача 'strict' в качестве значения приводит к возникновению исключения при любой ошибке кодирования, в то время как 'ignore' приводит к молчаливому игнорированию ошибок, а 'replace' использует U + FFFD, официальный символ замены, в случае каких-либо проблем.
  • Оператор exec и различные встроенные операторы eval(), getattr() и setattr(), также будут принимать строки Юникод, а также обычные строки. (Возможно, что в процессе исправления были упущены некоторые встроенные функции; если вы обнаружите встроенную функцию, которая принимает строки, но вообще не принимает строки Юникод, сообщить об этом как об ошибке.)

Новый модуль unicodedata предоставляет интерфейс для свойств символов Юникод. Например, 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 — это функция, которая принимает строку Юникод и возвращает 2-кортеж (string, length). string — это 8-битная строка, содержащая часть (возможно, всю) строки Юникод, преобразованной в заданную кодировку, а length сообщает, какая часть строки Юникод была преобразована.
  • decode_func является противоположностью encode_func, принимает 8-битную строку и возвращает 2-кортеж (ustring, length), состоящий из результирующей строки Юникод ustring и целого числа length, указывающего, сколько 8-битной строки было использовано.
  • stream_reader — это класс, поддерживающий декодирование входных данных из потока. stream_reader(file_obj) возвращает объект, который поддерживает методы read(), readline() и readlines(). Все данные методы будут транслировать из заданной кодировки и возвращать строки Юникод.
  • Аналогично, stream_writer — это класс, который поддерживает кодирование вывода в поток. stream_writer(file_obj) возвращает объект, который поддерживает методы write() и writelines(). Данные методы ожидают строки Юникод, переводя их в заданную кодировку на выходе.

Например, следующий код записывает строку Юникод в файл, кодируя её как 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 интерпретировать все строковые литералы как строковые литералы Юникод. Это предназначено для тестирования и проверки вашего кода Python на будущее, поскольку некоторые будущие версии Python могут отказаться от поддержки 8-битных строк и предоставлять только Юникод строки.

Списковые включения

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

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

# Имея список L, составляется список всех строк,
# содержащих подстроку 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 содержат последовательности, которые необходимо повторить. Последовательности не обязательно должны быть одинаковой длины, потому что они не повторяются параллельно, но слева направо; это объясняется более четко в следующих параграфах. Элементами сгенерированного списка будут последовательные значения expression. Последнее предложение if является необязательным; если присутствует, expression вычисляется и добавляется к результату только в том случае, если condition истинно.

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

for expr1 in sequence1:
    for expr2 in sequence2:
    ...
        for exprN in sequenceN:
             if (condition):
                  # Добавление значения
                  # выражения к полученному
                  # списку.

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

# Ошибка синтаксиса
[ x,y for x in seq1 for y in seq2]
# Правильно
[ (x,y) for x in seq1 for y in seq2]

Идея списковых включений изначально пришла из языка функционального программирования Haskell. Грег Юинг наиболее эффективно выступал за добавление их в 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. Добавление Юникод создавало трудности для модуля strop, поскольку все функции необходимо было переписать по порядку. принимать либо 8-битные строки, либо строки Юникод. Для таких функций, как string.replace(), которая принимает 3 строковых аргумента, это означает восемь возможных перестановок и, соответственно, сложный код.

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

>>> '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 - это кортеж позиционных аргументов,
    # kw - это словарь ключевых аргументов
    ...

Оператор 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 возвращает истина, если obj присутствует в последовательности seq; Python вычисляет это, просто перебирая каждый индекс последовательности, пока не будет найден либо obj, либо IndexError. Моше Задка предоставил патч, который добавляет волшебный метод __contains__() для обеспечения пользовательской реализации in. Кроме того, новые встроенные объекты, написанные на C, могут определять, что для них означает in, через новый слот в протоколе последовательности.

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

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

Сравнение a==b возвращает истина, поскольку две рекурсивные структуры данных изоморфны. См. ветку «мусорная корзина и 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() теперь принимают необязательный «базовый» параметр, когда первый аргумент является строкой. int('123', 10) возвращает 123, а int('123', 16) возвращает 291. int(123, 16) вызывает исключение TypeError с сообщением «невозможно преобразовать не строку с явной базой».

В модуль 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 с сообщением: «для добавления требуется ровно 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 документация была исправлена, а форма с несколькими аргументами просто помечена как устаревшая; это will будет снова исправлено в будущей версии 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 GiB; это заставило метод файловых объектов 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() числа с плавающей запятой, теперь используется другая точность форматирования, чем 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 в более крупное приложение. Если вы не имеете дело с Python C API, вы можете смело пропустить данный раздел.

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

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

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

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

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

Группа SIG по распространению утилит, возглавляемая Грегом Уордом, создала Distutils, систему, значительно упрощающую установку пакетов. Они образуют пакет distutils, новую часть стандартной библиотеки Python. В лучшем случае установка модуля Python из исходного кода потребует тех же шагов: сначала вы просто распаковываете tar-архив или 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 простого API для XML) предоставляет управляемый событиями интерфейс с некоторым сходством с xmllib, а DOM (объектная модель документа) предоставляет дерево , преобразующий 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

# Создать объект парсера
parser = sax.make_parser()

# Сказать, какой обработчик использовать
handler = SimpleHandler()
parser.setContentHandler( handler )

# Распарсить файл!
parser.parse( 'hamlet.xml' )

Для получения дополнительной информации обратитесь к документации по Python или XML HOWTO.

Поддержка DOM

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

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

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

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

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

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

# Удалить первого ребенка
root.removeChild( root.childNodes[0] )

# Переместить новый первый дочерний элемент в конец
root.appendChild( root.childNodes[0] )

# Вставить новый первый дочерний элемент (первоначально третий дочерний элемент)
# перед 20-м дочерним элементом.
root.insertBefore( root.childNodes[0], root.childNodes[20] )

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

Связь с PyXML

Группа специальных интересов XML некоторое время работала над кодом Python, связанным с XML. Его код, называемый PyXML, доступен на веб-страницах 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 также были изменены для поддержки URL-адресов https://, хотя никто не реализовал 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 теперь поддерживает отображение строк Юникод в виджетах Tk. Кроме того, Фредрик Лунд внес свой вклад в оптимизацию, которая значительно ускоряет такие операции, как create_line и create_polygon, особенно при использовании большого количества координат.

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

Как упоминалось ранее при обсуждении поддержки Юникод в версии 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: интерфейс для синтаксического анализатора Expat XML. (Предоставлено Полом Прескодом)

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

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

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