2.2.md
1> **Источник:** https://python-all.ru/3.7/whatsnew/2.2.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Что нового в Python 2.289**Автор**1011A.M. Kuchling1213## Введение1415Эта статья объясняет новые возможности Python 2.2.2, выпущенного 14 октября 2002 года. Python 2.2.2 – это выпуск с исправлением ошибок Python 2.2, первоначально вышедшего 21 декабря 2001 года.1617Python 2.2 можно считать «релизом по наведению порядка». В нём есть несколько совершенно новых возможностей, таких как генераторы и итераторы, но большинство изменений, какими бы значительными и далеко идущими они ни были, направлены на устранение непоследовательностей и тёмных углов в дизайне языка.1819Эта статья не претендует на полноценную спецификацию новых возможностей, а даёт удобный обзор. За полными подробностями обращайтесь к документации Python 2.2, например, к [Справочнику по библиотеке Python](https://python-all.ru/3.7/whatsnew/2.2.html) и [Справочному руководству Python](https://python-all.ru/3.7/whatsnew/2.2.html). Если вы хотите понять полную реализацию и обоснование дизайна какого-либо изменения, обратитесь к соответствующему PEP для этой новой возможности.2021## PEP 252 и 253: Изменения типов и классов2223Самые большие и далеко идущие изменения в Python 2.2 касаются модели объектов и классов. Изменения должны быть обратно совместимы, поэтому ваш код, скорее всего, продолжит работать без изменений, но эти изменения дают потрясающие новые возможности. Перед тем как приступить к самому длинному и сложному разделу этой статьи, я дам обзор изменений и выскажу несколько замечаний.2425Давным-давно я написал веб-страницу с перечнем недостатков дизайна Python. Одним из самых значительных недостатков была невозможность наследования от типов Python, реализованных на C. В частности, невозможно наследовать от встроенных типов, поэтому нельзя просто взять и унаследовать, скажем, список, чтобы добавить к нему один полезный метод. Модуль `UserList` предоставляет класс, который поддерживает все методы списков и от которого можно наследовать, но существует много кода на C, который ожидает обычный список Python и не примет экземпляр `UserList`.2627Python 2.2 исправляет это, и в процессе добавляет несколько захватывающих новых возможностей. Краткое резюме:2829- Вы можете наследовать встроенные типы, такие как списки и даже целые числа, и ваши подклассы должны работать везде, где требуется исходный тип.30- Теперь можно определять статические методы и методы класса, в дополнение к методам экземпляра, доступным в предыдущих версиях Python.31- Также можно автоматически вызывать методы при доступе к атрибуту экземпляра или его установке, используя новый механизм, называемый *свойствами*. Многие случаи использования [`__getattr__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__getattr__) можно переписать на свойства, что сделает код проще и быстрее. В качестве небольшого побочного преимущества, атрибуты теперь могут иметь докстринги.32- Список допустимых атрибутов экземпляра можно ограничить определённым набором с помощью *слотов*, что позволяет защититься от опечаток и, возможно, сделать больше оптимизаций в будущих версиях Python.3334Некоторые пользователи выразили обеспокоенность по поводу всех этих изменений. «Конечно, – говорят они, – новые функции интересны и позволяют делать разные трюки, которые были невозможны в предыдущих версиях Python, но они также усложняют язык». Некоторые говорят, что всегда рекомендовали Python за его простоту, и чувствуют, что эта простота теряется.3536Лично я считаю, что беспокоиться не о чем. Многие новые возможности довольно эзотеричны, и вы можете писать много кода на Python, даже не подозревая о них. Написание простого класса не сложнее, чем раньше, так что вам не нужно утруждать себя их изучением или обучением, если они действительно не нужны. Некоторые очень сложные задачи, которые ранее были возможны только на C, теперь можно решать на чистом Python, и, на мой взгляд, это только к лучшему.3738Я не буду пытаться охватить каждый частный случай и мелкое изменение, необходимые для работы новых функций. Вместо этого данный раздел опишет только общую картину. Смотрите раздел [Связанные ссылки](https://python-all.ru/3.7/whatsnew/2.2.html#sect-rellinks), «Связанные ссылки», для получения дополнительных источников информации о новой объектной модели Python 2.2.3940### Старые и новые классы4142Прежде всего, следует знать, что Python 2.2 действительно имеет два вида классов: классические (или старые) классы и классы нового стиля. Модель старых классов в точности такая же, как в более ранних версиях Python. Все новые возможности, описанные в этом разделе, применимы только к классам нового стиля. Это разделение не предполагается сохранять навсегда; в конечном итоге старые классы будут удалены, возможно, в Python 3.0.4344Итак, как определить класс нового стиля? Для этого нужно унаследоваться от существующего класса нового стиля. Большинство встроенных типов Python, такие как целые числа, списки, словари и даже файлы, теперь являются классами нового стиля. Также был добавлен класс нового стиля с именем [`object`](https://python-all.ru/3.7/library/functions.html#object), базовый класс для всех встроенных типов, так что если ни один встроенный тип не подходит, можно просто унаследоваться от [`object`](https://python-all.ru/3.7/library/functions.html#object):4546```python47class C(object):48 def __init__ (self):49 ...50 ...51```5253Это означает, что операторы [`class`](https://python-all.ru/3.7/reference/compound_stmts.html#class), не имеющие базовых классов, в Python 2.2 всегда являются классическими классами. (На самом деле это можно изменить, установив переменную уровня модуля с именем `__metaclass__` – подробности см. в [**PEP 253**](https://python-all.ru/3.7/whatsnew/2.2.html) – но проще просто унаследоваться от [`object`](https://python-all.ru/3.7/library/functions.html#object).)5455Объекты типов для встроенных типов доступны как встроенные объекты, названные с помощью хитроумного трюка. В Python всегда были встроенные функции [`int()`](https://python-all.ru/3.7/library/functions.html#int), [`float()`](https://python-all.ru/3.7/library/functions.html#float) и [`str()`](https://python-all.ru/3.7/library/stdtypes.html#str). В версии 2.2 они больше не являются функциями, а представляют собой объекты типов, которые ведут себя как фабрики при вызове.5657```python58>>> int59<type 'int'>60>>> int('123')6112362```6364Для полноты набора типов были добавлены новые объекты типов, такие как [`dict()`](https://python-all.ru/3.7/library/stdtypes.html#dict) и `file()`. Вот более интересный пример: добавление метода `lock()` к файловым объектам:6566```python67class LockableFile(file):68 def lock (self, operation, length=0, start=0, whence=0):69 import fcntl70 return fcntl.lockf(self.fileno(), operation,71 length, start, whence)72```7374Сейчас устаревший модуль `posixfile` содержал класс, который эмулировал все методы файлового объекта и также добавлял метод `lock()`, но этот класс нельзя было передать внутренним функциям, ожидающим встроенный файл, что теперь возможно с нашим новым `LockableFile`.7576### Дескрипторы7778В предыдущих версиях Python не было единого способа узнать, какие атрибуты и методы поддерживаются объектом. Существовали неформальные соглашения, такие как определение атрибутов `__members__` и `__methods__`, содержащих списки имён, но часто автор расширения или класса не утруждал себя их определением. Можно было прибегнуть к проверке [`__dict__`](https://python-all.ru/3.7/library/stdtypes.html#object.__dict__) объекта, но при использовании наследования классов или произвольного хука [`__getattr__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__getattr__) это могло быть неточным.7980Одна большая идея, лежащая в основе новой модели классов, заключается в формализации API для описания атрибутов объекта с помощью *дескрипторов*. Дескрипторы определяют значение атрибута, указывая, является ли он методом или полем. Благодаря API дескрипторов становятся возможными статические методы, методы класса, а также более экзотические конструкции.8182Дескрипторы атрибутов – это объекты, которые находятся внутри объектов классов и имеют несколько собственных атрибутов:8384- [`__name__`](https://python-all.ru/3.7/library/stdtypes.html#definition.__name__) – это имя атрибута.85- `__doc__` – это докстринг атрибута.86- `__get__(object)` – это метод, который извлекает значение атрибута из *объекта*.87- `__set__(object, value)` устанавливает атрибут *объекта* в *значение*.88- `__delete__(object, value)` удаляет атрибут *значение* объекта *объекта*.8990Например, при записи `obj.x` Python выполняет следующие шаги:9192```python93descriptor = obj.__class__.x94descriptor.__get__(obj)95```9697Для методов, `descriptor.__get__()` возвращает временный объект, который можно вызывать, и упаковывает экземпляр и метод, который должен быть вызван на нём. Именно поэтому теперь возможны статические методы и методы класса; у них есть дескрипторы, которые упаковывают только метод, или метод и класс. Краткое объяснение этих новых видов методов: статическим методам не передаётся экземпляр, поэтому они похожи на обычные функции. Методам класса передаётся класс объекта, но не сам объект. Статические методы и методы класса определяются так:9899```python100class C(object):101 def f(arg1, arg2):102 ...103 f = staticmethod(f)104105 def g(cls, arg1, arg2):106 ...107 g = classmethod(g)108```109110Функция [`staticmethod()`](https://python-all.ru/3.7/library/functions.html#staticmethod) принимает функцию `f()` и возвращает её, упакованную в дескриптор, чтобы её можно было сохранить в объекте класса. Можно было бы ожидать специального синтаксиса для создания таких методов (`def static f`, `defstatic f()` или чего-то подобного), но такого синтаксиса пока не определено; это оставлено для будущих версий Python.111112Многие новые возможности, такие как слоты (slots) и свойства (properties), также реализованы как новые виды дескрипторов, и написать класс дескриптора, делающий что-то новое, несложно. Например, можно написать класс дескриптора, который позволяет записывать предусловия и постусловия в стиле языка Eiffel для метода. Класс, использующий эту возможность, может быть определён следующим образом:113114```python115from eiffel import eiffelmethod116117class C(object):118 def f(self, arg1, arg2):119 # Собственно функция120 ...121 def pre_f(self):122 # Проверить предусловия123 ...124 def post_f(self):125 # Проверить постусловия126 ...127128 f = eiffelmethod(f, pre_f, post_f)129```130131Обратите внимание, что человеку, использующему новые `eiffelmethod()`, не нужно ничего понимать в дескрипторах. Поэтому я считаю, что новые возможности не увеличивают базовую сложность языка. Найдётся несколько волшебников, которым нужно знать о них, чтобы написать `eiffelmethod()` или ZODB, или что-то ещё, но большинство пользователей просто будут писать код поверх получившихся библиотек и игнорировать детали реализации.132133### Множественное наследование: правило ромба134135Множественное наследование стало более полезным благодаря изменению правил разрешения имён. Рассмотрим следующий набор классов (диаграмма взята из [**PEP 253**](https://python-all.ru/3.7/whatsnew/2.2.html) Гвидо ван Россума):136137```python138 class A:139 ^ ^ def save(self): ...140 / \141 / \142 / \143 / \144class B class C:145 ^ ^ def save(self): ...146 \ /147 \ /148 \ /149 \ /150 class D151```152153Правило поиска для классических классов простое, но не очень умное: базовые классы просматриваются в глубину, слева направо. Обращение к `D.save()` будет искать в классах `D`, `B`, а затем `A`, где будет найден `save()` и возвращён. `C.save()` не будет найден вообще. Это плохо, потому что если метод `save()` `C` сохраняет некоторое внутреннее состояние, специфичное для `C`, то его невызов приведёт к тому, что это состояние никогда не будет сохранено.154155Классы нового стиля следуют другому алгоритму, который немного сложнее объяснить, но делает правильное дело в этой ситуации. (Обратите внимание, что Python 2.3 изменяет этот алгоритм на тот, который в большинстве случаев даёт те же результаты, но даёт более полезные результаты для действительно сложных графов наследования.)1561571. Перечислить все базовые классы, следуя классическому правилу поиска, и включать класс несколько раз, если он посещается повторно. В приведённом примере список посещённых классов: \[`D`, `B`, `A`, `C`, `A`\].1582. Проверить список на наличие дублирующихся классов. Если таковые найдены, удалить все вхождения, кроме одного, оставив *последнее* в списке. В приведённом примере список становится \[`D`, `B`, `C`, `A`\] после удаления дубликатов.159160Следуя этому правилу, обращение к `D.save()` вернёт `C.save()`, что и является нужным поведением. Это правило поиска совпадает с правилом, используемым в Common Lisp. Новая встроенная функция [`super()`](https://python-all.ru/3.7/library/functions.html#super) предоставляет способ получить суперклассы класса без необходимости повторной реализации алгоритма Python. Наиболее часто используемой формой будет `super(class, obj)`, которая возвращает связанный объект суперкласса (не сам объект класса). Эта форма будет использоваться в методах для вызова метода суперкласса; например, метод `save()` `D` будет выглядеть следующим образом:161162```python163class D (B,C):164 def save (self):165 # Вызвать .save() родительского класса166 super(D, self).save()167 # Сохранить приватные данные D здесь168 ...169```170171[`super()`](https://python-all.ru/3.7/library/functions.html#super) также может возвращать несвязанные объекты суперкласса при вызове как `super(class)` или `super(class1, class2)`, но это, вероятно, не будет часто полезно.172173### Доступ к атрибутам174175Немало сложных классов Python определяют перехватчики для доступа к атрибутам с помощью [`__getattr__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__getattr__); чаще всего это делается для удобства, чтобы сделать код более читаемым за счёт автоматического преобразования доступа к атрибуту, такого как `obj.parent`, в вызов метода, такой как `obj.get_parent`. Python 2.2 добавляет несколько новых способов управления доступом к атрибутам.176177Во-первых, `__getattr__(attr_name)` по-прежнему поддерживается классами нового стиля, и в нём ничего не изменилось. Как и прежде, он будет вызываться при попытке доступа к `obj.foo`, если в словаре экземпляра не найден атрибут с именем `foo`.178179Классы нового стиля также поддерживают новый метод – `__getattribute__(attr_name)`. Разница между двумя методами в том, что [`__getattribute__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__getattribute__) вызывается *всегда* при любом доступе к атрибуту, тогда как старый [`__getattr__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__getattr__) вызывается только если `foo` не найден в словаре экземпляра.180181Однако поддержка *свойств (properties)* в Python 2.2 часто будет более простым способом перехвата обращений к атрибутам. Написание метода [`__getattr__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__getattr__) – дело сложное, потому что для избежания рекурсии внутри него нельзя использовать обычные обращения к атрибутам, и вместо этого приходится работать с содержимым [`__dict__`](https://python-all.ru/3.7/library/stdtypes.html#object.__dict__). Методы [`__getattr__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__getattr__) также вызываются Python при проверке других методов, таких как [`__repr__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__repr__) или `__coerce__()`, поэтому их нужно писать с учётом этого. Наконец, вызов функции при каждом доступе к атрибуту приводит к существенному снижению производительности.182183[`property`](https://python-all.ru/3.7/library/functions.html#property) – это новый встроенный тип, который объединяет три функции: получения, установки или удаления атрибута, а также строку документации. Например, если требуется определить атрибут `size`, который вычисляется, но также может быть установлен, можно написать:184185```python186class C(object):187 def get_size (self):188 result = ... computation ...189 return result190 def set_size (self, size):191 ... compute something based on the size192 and set internal state appropriately ...193194 # Определить свойство. Метод 'delete this attribute'195 # метод определён как None, поэтому атрибут196 # не может быть удалён.197 size = property(get_size, set_size,198 None,199 "Storage size of this instance")200```201202Это, безусловно, понятнее и проще в написании, чем пара методов [`__getattr__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__getattr__)/[`__setattr__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__setattr__), которые проверяют атрибут `size` и обрабатывают его особым образом, извлекая все остальные атрибуты из [`__dict__`](https://python-all.ru/3.7/library/stdtypes.html#object.__dict__) экземпляра. Кроме того, доступ к `size` – единственный, который требует вызова функции, поэтому обращения к другим атрибутам выполняются на обычной скорости.203204Наконец, можно ограничить список атрибутов, к которым можно обращаться у объекта, с помощью нового атрибута класса [`__slots__`](https://python-all.ru/3.7/reference/datamodel.html#object.__slots__). Объекты Python обычно очень динамичны; в любой момент можно определить новый атрибут у экземпляра, просто написав `obj.new_attr=1`. Класс нового стиля может определить атрибут класса с именем [`__slots__`](https://python-all.ru/3.7/reference/datamodel.html#object.__slots__), чтобы ограничить допустимые атрибуты определённым набором имён. Пример прояснит это:205206```python207>>> class C(object):208... __slots__ = ('template', 'name')209...210>>> obj = C()211>>> print obj.template212None213>>> obj.template = 'Test'214>>> print obj.template215Test216>>> obj.newattr = None217Traceback (most recent call last):218 File "<stdin>", line 1, in ?219AttributeError: 'C' object has no attribute 'newattr'220```221222Обратите внимание, что при попытке присвоить значение атрибуту, не указанному в [`__slots__`](https://python-all.ru/3.7/reference/datamodel.html#object.__slots__), возникает [`AttributeError`](https://python-all.ru/3.7/library/exceptions.html#AttributeError).223224### Связанные ссылки225226Этот раздел был лишь кратким обзором новых возможностей, дающим достаточно объяснений, чтобы начать программировать, но многие детали были упрощены или опущены. Куда обратиться, чтобы получить более полную картину?227228[https://docs.python.org/dev/howto/descriptor.html](https://python-all.ru/3.7/dev/howto/descriptor.html) – это подробное учебное введение в дескрипторы, написанное Гвидо ван Россумом. Если моё описание разожгло ваш аппетит, прочитайте это руководство следующим, так как оно вдаётся в гораздо более подробные детали о новых возможностях, оставаясь при этом достаточно лёгким для чтения.229230Далее есть два соответствующих PEP: [**PEP 252**](https://python-all.ru/3.7/whatsnew/2.2.html) и [**PEP 253**](https://python-all.ru/3.7/whatsnew/2.2.html). [**PEP 252**](https://python-all.ru/3.7/whatsnew/2.2.html) называется «Making Types Look More Like Classes» и описывает API дескрипторов. [**PEP 253**](https://python-all.ru/3.7/whatsnew/2.2.html) называется «Subtyping Built-in Types» и описывает изменения в объектах типов, которые делают возможным создание подтипов встроенных объектов. [**PEP 253**](https://python-all.ru/3.7/whatsnew/2.2.html) – более сложный из двух PEP, и в некоторых местах необходимые объяснения типов и метатипов могут вызвать головную боль. Оба PEP были написаны и реализованы Гвидо ван Россумом при значительной помощи остальной команды Zope Corp.231232Наконец, есть высший авторитет: исходный код. Большая часть механизмов обработки типов находится в `Objects/typeobject.c`, но обращаться к нему следует только после того, как исчерпаны все другие возможности, включая отправку вопроса в python-list или python-dev.233234## PEP 234: Итераторы235236Ещё одно значительное дополнение в 2.2 – это интерфейс итерации на уровнях C и Python. Объекты могут определять, как по ним можно итерироваться вызывающим кодом.237238В версиях Python до 2.1 обычным способом заставить `for item in obj` работать было определение метода [`__getitem__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__getitem__), который выглядел примерно так:239240```python241def __getitem__(self, index):242 return <next item>243```244245[`__getitem__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__getitem__) правильнее использовать для определения операции индексирования объекта, чтобы можно было писать `obj[5]` для получения шестого элемента. Это немного сбивает с толку, когда вы используете это только для поддержки циклов [`for`](https://python-all.ru/3.7/reference/compound_stmts.html#for). Рассмотрим некий файлоподобный объект, по которому нужно итерироваться; параметр *index* по сути бессмысленен, так как класс, вероятно, предполагает, что будет сделана серия вызовов [`__getitem__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__getitem__) с увеличивающимся на единицу *index*. Другими словами, наличие метода [`__getitem__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__getitem__) не означает, что использование `file[5]` для произвольного доступа к шестому элементу сработает, хотя на самом деле должно.246247В Python 2.2 итерацию можно реализовать отдельно, а методы [`__getitem__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__getitem__) можно ограничить классами, которые действительно поддерживают произвольный доступ. Основная идея итераторов проста. Новая встроенная функция `iter(obj)` или `iter(C, sentinel)` используется для получения итератора. `iter(obj)` возвращает итератор для объекта *obj*, а `iter(C, sentinel)` возвращает итератор, который будет вызывать вызываемый объект *C* до тех пор, пока он не вернёт *sentinel*, сигнализируя об окончании итератора.248249Классы Python могут определять метод [`__iter__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__iter__), который должен создавать и возвращать новый итератор для объекта; если объект сам является своим итератором, этот метод может просто вернуть `self`. В частности, итераторы обычно являются собственными итераторами. Расширения, реализованные на C, могут реализовать функцию [`tp_iter`](https://python-all.ru/3.7/c-api/typeobj.html#c.PyTypeObject.tp_iter) для возврата итератора, а расширения, которые хотят вести себя как итераторы, могут определить функцию [`tp_iternext`](https://python-all.ru/3.7/c-api/typeobj.html#c.PyTypeObject.tp_iternext).250251Итак, что же на самом деле делают итераторы? У них есть один обязательный метод [`next()`](https://python-all.ru/3.7/library/functions.html#next), который не принимает аргументов и возвращает следующее значение. Когда больше нечего возвращать, вызов [`next()`](https://python-all.ru/3.7/library/functions.html#next) должен возбуждать исключение [`StopIteration`](https://python-all.ru/3.7/library/exceptions.html#StopIteration).252253```python254>>> L = [1,2,3]255>>> i = iter(L)256>>> print i257<iterator object at 0x8116870>258>>> i.next()2591260>>> i.next()2612262>>> i.next()2633264>>> i.next()265Traceback (most recent call last):266 File "<stdin>", line 1, in ?267StopIteration268>>>269```270271В Python 2.2 оператор [`for`](https://python-all.ru/3.7/reference/compound_stmts.html#for) больше не требует последовательности; он ожидает объект, для которого [`iter()`](https://python-all.ru/3.7/library/functions.html#iter) вернёт итератор. Для обратной совместимости и удобства итератор автоматически создаётся для последовательностей, которые не реализуют [`__iter__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__iter__) или слот [`tp_iter`](https://python-all.ru/3.7/c-api/typeobj.html#c.PyTypeObject.tp_iter), так что `for i in [1,2,3]` по-прежнему будет работать. Везде, где интерпретатор Python выполняет цикл по последовательности, он теперь использует протокол итератора. Это означает, что можно делать, например, следующее:272273```python274>>> L = [1,2,3]275>>> i = iter(L)276>>> a,b,c = i277>>> a,b,c278(1, 2, 3)279```280281Поддержка итераторов была добавлена для некоторых базовых типов Python. Вызов [`iter()`](https://python-all.ru/3.7/library/functions.html#iter) для словаря вернёт итератор, который перебирает его ключи:282283```python284>>> m = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,285... 'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12}286>>> for key in m: print key, m[key]287...288Mar 3289Feb 2290Aug 8291Sep 9292May 5293Jun 6294Jul 7295Jan 1296Apr 4297Nov 11298Dec 12299Oct 10300```301302Это поведение по умолчанию. Если нужно перебрать ключи, значения или пары ключ/значение, можно явно вызвать методы `iterkeys()`, `itervalues()` или `iteritems()`, чтобы получить соответствующий итератор. В связанном небольшом изменении оператор [`in`](https://python-all.ru/3.7/reference/expressions.html#in) теперь работает со словарями, так что `key in dict` теперь эквивалентно `dict.has_key(key)`.303304Файлы также предоставляют итератор, который вызывает метод [`readline()`](https://python-all.ru/3.7/library/readline.html#module-readline), пока в файле есть строки. Это означает, что теперь можно читать каждую строку файла с помощью такого кода:305306```python307for line in file:308 # сделать что-то для каждой строки309 ...310```311312Обратите внимание, что итератор можно перемещать только вперёд; нет способа получить предыдущий элемент, сбросить итератор или сделать его копию. Объект-итератор может предоставлять такие дополнительные возможности, но протокол итератора требует только метод [`next()`](https://python-all.ru/3.7/library/functions.html#next).313314> **См. также**315>316> **[**PEP 234**](https://python-all.ru/3.7/whatsnew/2.2.html) – Итераторы**317>318> Авторы: Ка-Пинг Йи и Гвидо ван Россум; реализовано командой Python Labs, в основном Гвидо и Тимом Петерсом.319320## PEP 255: Простые генераторы321322Генераторы – ещё одна новая возможность, которая связана с введением итераторов.323324Вы, несомненно, знакомы с тем, как работают вызовы функций в Python или C. Когда вызывается функция, она получает отдельное пространство имён, в котором создаются её локальные переменные. Когда функция достигает оператора [`return`](https://python-all.ru/3.7/reference/simple_stmts.html#return), локальные переменные уничтожаются, а полученное значение возвращается вызывающему. Последующий вызов той же функции получит новый набор локальных переменных. Но что, если бы локальные переменные не уничтожались при выходе из функции? Что, если бы можно было возобновить выполнение функции с того места, где она остановилась? Это и обеспечивают генераторы; их можно рассматривать как возобновляемые функции.325326Вот простейший пример функции-генератора:327328```python329def generate_ints(N):330 for i in range(N):331 yield i332```333334Для генераторов было введено новое ключевое слово [`yield`](https://python-all.ru/3.7/reference/simple_stmts.html#yield). Любая функция, содержащая оператор `yield`, является генераторной функцией; это обнаруживается байт-код-компилятором Python, который компилирует такую функцию особым образом. Поскольку было введено новое ключевое слово, генераторы должны быть явно включены в модуле с помощью оператора `from __future__ import generators` в начале исходного кода модуля. В Python 2.3 этот оператор станет ненужным.335336При вызове генераторной функции она возвращает не одно значение, а объект-генератор, поддерживающий протокол итератора. При выполнении оператора [`yield`](https://python-all.ru/3.7/reference/simple_stmts.html#yield) генератор выдаёт значение `i`, подобно оператору [`return`](https://python-all.ru/3.7/reference/simple_stmts.html#return). Большая разница между `yield` и оператором `return` заключается в том, что при достижении `yield` состояние выполнения генератора приостанавливается, а локальные переменные сохраняются. При следующем вызове метода `next()` генератора функция возобновляет выполнение сразу после оператора `yield`. (По сложным причинам оператор `yield` не допускается внутри блока `try` оператора [`try`](https://python-all.ru/3.7/reference/compound_stmts.html#try)…[`finally`](https://python-all.ru/3.7/reference/compound_stmts.html#finally); прочтите [**PEP 255**](https://python-all.ru/3.7/whatsnew/2.2.html) для полного объяснения взаимодействия между `yield` и исключениями.)337338Вот пример использования генератора `generate_ints()`:339340```python341>>> gen = generate_ints(3)342>>> gen343<generator object at 0x8117f90>344>>> gen.next()3450346>>> gen.next()3471348>>> gen.next()3492350>>> gen.next()351Traceback (most recent call last):352 File "<stdin>", line 1, in ?353 File "<stdin>", line 2, in generate_ints354StopIteration355```356357Можно также написать `for i in generate_ints(5)` или `a,b,c = generate_ints(3)`.358359Внутри генераторной функции оператор [`return`](https://python-all.ru/3.7/reference/simple_stmts.html#return) может использоваться только без значения и сигнализирует об окончании последовательности значений; после этого генератор не может вернуть никаких дополнительных значений. `return` со значением, например `return 5`, является синтаксической ошибкой внутри генераторной функции. Конец результатов генератора также можно указать вручную, возбудив [`StopIteration`](https://python-all.ru/3.7/library/exceptions.html#StopIteration), или просто позволив потоку выполнения дойти до конца функции.360361Эффекта генераторов можно добиться вручную, написав собственный класс и сохранив все локальные переменные генератора как переменные экземпляра. Например, возврат списка целых чисел можно было бы реализовать, установив `self.count` в 0 и заставив метод [`next()`](https://python-all.ru/3.7/library/functions.html#next) увеличивать `self.count` и возвращать его. Однако для сколь-нибудь сложного генератора написание соответствующего класса было бы гораздо более запутанным. `Lib/test/test_generators.py` содержит ряд более интересных примеров. Самый простой из них реализует симметричный обход дерева с помощью рекурсивных генераторов.362363```python364# Рекурсивный генератор, порождающий листья дерева в порядке in-order.365def inorder(t):366 if t:367 for x in inorder(t.left):368 yield x369 yield t.label370 for x in inorder(t.right):371 yield x372```373374Два других примера в `Lib/test/test_generators.py` дают решения задачи о N ферзях (размещение N ферзей на шахматной доске N×N так, чтобы ни один ферзь не угрожал другому) и задачи об обходе коня (маршрут, по которому конь посещает каждую клетку доски N×N, не посещая ни одну клетку дважды).375376Идея генераторов пришла из других языков программирования, особенно Icon ([https://www.cs.arizona.edu/icon/](https://python-all.ru/3.7/whatsnew/2.2.html)), где идея генераторов является центральной. В Icon каждое выражение и вызов функции ведут себя как генератор. Один пример из «An Overview of the Icon Programming Language» по адресу [https://www.cs.arizona.edu/icon/docs/ipd266.htm](https://python-all.ru/3.7/whatsnew/2.2.html) даёт представление о том, как это выглядит:377378```python379sentence := "Store it in the neighboring harbor"380if (i := find("or", sentence)) > 5 then write(i)381```382383В Icon функция `find()` возвращает индексы, по которым найдена подстрока «or»: 3, 23, 33. В операторе [`if`](https://python-all.ru/3.7/reference/compound_stmts.html#if) переменной `i` сначала присваивается значение 3, но 3 меньше 5, поэтому сравнение не удаётся, и Icon повторяет попытку со вторым значением 23. 23 больше 5, поэтому теперь сравнение успешно, и код выводит на экран значение 23.384385Python не заходит так далеко, как Icon, в принятии генераторов в качестве центральной концепции. Генераторы считаются новой частью ядра языка Python, но их изучение или использование не является обязательным; если они не решают ваших задач, можете их игнорировать. Одной из новых особенностей интерфейса Python по сравнению с Icon является то, что состояние генератора представляется как конкретный объект (итератор), который можно передавать другим функциям или хранить в структуре данных.386387> **См. также**388>389> **[**PEP 255**](https://python-all.ru/3.7/whatsnew/2.2.html) - Simple Generators**390>391> Авторы: Нил Шеменауэр, Тим Питерс, Магнус Ли Хетланд. Реализовано в основном Нилом Шеменауэром и Тимом Питерсом, с дополнительными исправлениями от команды Python Labs.392393## PEP 237: Унификация длинных целых и целых чисел394395В последних версиях различие между обычными целыми (32-битными на большинстве машин) и длинными целыми (произвольного размера) стало раздражать. Например, на платформах, поддерживающих файлы размером более `2**32` байт, метод `tell()` файловых объектов должен возвращать длинное целое. Однако некоторые части Python ожидали обычные целые и выдавали ошибку, если вместо них передавалось длинное целое. Например, в Python 1.5 в качестве индекса среза можно было использовать только обычные целые, и `'abc'[1L:]` вызывало исключение [`TypeError`](https://python-all.ru/3.7/library/exceptions.html#TypeError) с сообщением 'slice index must be int'.396397Python 2.2 будет автоматически преобразовывать короткие целые в длинные по мере необходимости. Суффикс «L» больше не нужен для обозначения литерала длинного целого, так как компилятор теперь сам выбирает подходящий тип. (Использование суффикса «L» будет не рекомендоваться в будущих версиях Python 2.x, вызывая предупреждение в Python 2.4, и, вероятно, удалено в Python 3.0.) Многие операции, которые раньше вызывали [`OverflowError`](https://python-all.ru/3.7/library/exceptions.html#OverflowError), теперь будут возвращать длинное целое. Например:398399```python400>>> 12345678901234011234567890123L402>>> 2 ** 6440318446744073709551616L404```405406В большинстве случаев целые и длинные целые теперь обрабатываются одинаково. Вы всё ещё можете различать их с помощью встроенной функции [`type()`](https://python-all.ru/3.7/library/functions.html#type), но это редко требуется.407408> **См. также**409>410> **[**PEP 237**](https://python-all.ru/3.7/whatsnew/2.2.html) – Унификация длинных целых и целых чисел**411>412> Авторы: Моше Задка и Гвидо ван Россум. В основном реализовано Гвидо ван Россумом.413414## PEP 238: Изменение оператора деления415416Самое противоречивое изменение в Python 2.2 знаменует начало усилий по исправлению старого проектного недостатка, существовавшего в Python с самого начала. В настоящее время оператор деления Python, `/`, ведёт себя как оператор деления в C, когда оба операнда целые: он возвращает целочисленный результат, усечённый вниз при наличии дробной части. Например, `3/2` равно 1, а не 1,5, и `(-1)/2` равно -1, а не -0,5. Это означает, что результаты деления могут неожиданно различаться в зависимости от типа двух операндов, а из-за динамической типизации Python бывает трудно определить возможные типы операндов.417418(Споры ведутся о том, является ли это *действительно* проектным недостатком и стоит ли ломать существующий код для его исправления. Это вызвало бесконечные обсуждения в python-dev, а в июле 2001 года вылилось в шквал едко-саркастических сообщений в *comp.lang.python*. Я не буду выступать ни за одну из сторон и ограничусь описанием того, что реализовано в 2.2. Прочтите [**PEP 238**](https://python-all.ru/3.7/whatsnew/2.2.html) для сводки аргументов и контраргументов.)419420Поскольку это изменение может нарушить работу существующего кода, его внедряют очень постепенно. Переход начинается в Python 2.2, но полное переключение произойдёт только в Python 3.0.421422Сначала я позаимствую несколько терминов из [**PEP 238**](https://python-all.ru/3.7/whatsnew/2.2.html). «Истинное деление» – это деление, знакомое большинству не-программистов: 3/2 равно 1,5, 1/4 равно 0,25 и так далее. «Деление с округлением вниз» (floor division) – это то, что оператор `/` в Python сейчас делает с целочисленными операндами; результат – это округлённое вниз значение, возвращаемое истинным делением. «Классическое деление» – это текущее смешанное поведение `/`; оно возвращает результат деления с округлением вниз, когда операнды – целые числа, и результат истинного деления, когда один из операндов – число с плавающей запятой.423424Вот изменения, которые вводит Python 2.2:425426- Новый оператор `//` – это оператор деления с округлением вниз. (Да, мы знаем, что он похож на символ комментария в C++.) `//` *всегда* выполняет деление с округлением вниз независимо от типов операндов, поэтому `1 // 2` равно 0, а `1.0 // 2.0` также равно 0,0.427428 `//` всегда доступен в Python 2.2; его не нужно включать с помощью оператора `__future__`.429- Если включить `from __future__ import division` в модуль, оператор `/` будет изменён так, чтобы возвращать результат истинного деления, поэтому `1/2` станет равно 0,5. Без оператора `__future__` `/` по-прежнему означает классическое деление. Значение по умолчанию `/` не изменится до Python 3.0.430- Классы могут определять методы с именами [`__truediv__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__truediv__) и [`__floordiv__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__floordiv__) для перегрузки двух операторов деления. На уровне C также есть слоты в структуре [`PyNumberMethods`](https://python-all.ru/3.7/c-api/typeobj.html#c.PyNumberMethods), чтобы типы-расширения могли определять эти операторы.431- Python 2.2 поддерживает несколько аргументов командной строки для проверки, будет ли код работать с изменённой семантикой деления. Запуск python с флагом `-Q warn` будет вызывать предупреждение каждый раз, когда деление применяется к двум целым числам. Это можно использовать, чтобы найти код, на который повлияло изменение, и исправить его. По умолчанию Python 2.2 просто выполняет классическое деление без предупреждения; предупреждение будет включено по умолчанию в Python 2.3.432433> **См. также**434>435> **[**PEP 238**](https://python-all.ru/3.7/whatsnew/2.2.html) – Изменение оператора деления**436>437> Написан Моше Задкой и Гвидо ван Россумом. Реализован Гвидо ван Россумом.438439## Изменения в поддержке Unicode440441Поддержка Unicode в Python 2.2 была немного расширена. Строки Unicode обычно хранятся как UCS-2, то есть 16-битные целые числа без знака. Python 2.2 также можно скомпилировать с использованием UCS-4 (32-битные целые числа без знака) в качестве внутренней кодировки, передав `--enable-unicode=ucs4` скрипту configure. (Также можно указать `--disable-unicode`, чтобы полностью отключить поддержку Unicode.)442443При компиляции для использования UCS-4 («широкий Python») интерпретатор может напрямую работать с символами Unicode от U+000000 до U+110000, поэтому диапазон допустимых значений для функции `unichr()` соответственно расширяется. При использовании интерпретатора, скомпилированного для UCS-2 («узкий Python»), значения больше 65535 по-прежнему будут заставлять `unichr()` вызывать исключение [`ValueError`](https://python-all.ru/3.7/library/exceptions.html#ValueError). Всё это описано в [**PEP 261**](https://python-all.ru/3.7/whatsnew/2.2.html), «Поддержка «широких» символов Unicode»; обратитесь к нему за подробностями.444445Ещё одно изменение объяснить проще. С момента появления строки Unicode поддерживали метод `encode()` для преобразования строки в выбранную кодировку, например UTF-8 или Latin-1. В Python 2.2 для 8-битных строк (но не для строк Unicode) был добавлен симметричный метод `decode([*encoding*])`. `decode()` предполагает, что строка находится в указанной кодировке, и декодирует её, возвращая то, что возвращает кодек.446447С помощью этой новой функции были добавлены кодеки для задач, не связанных напрямую с Unicode. Например, добавлены кодеки для uu-кодирования, кодирования base64 из MIME и сжатия с помощью модуля [`zlib`](https://python-all.ru/3.7/library/zlib.html#module-zlib):448449```python450>>> s = """Here is a lengthy piece of redundant, overly verbose,451... and repetitive text.452... """453>>> data = s.encode('zlib')454>>> data455'x\x9c\r\xc9\xc1\r\x80 \x10\x04\xc0?Ul...'456>>> data.decode('zlib')457'Here is a lengthy piece of redundant, overly verbose,\nand repetitive text.\n'458>>> print s.encode('uu')459begin 666 <data>460M2&5R92!I<R!A(&QE;F=T:'D@<&EE8V4@;V8@<F5D=6YD86YT+"!O=F5R;'D@461>=F5R8F]S92P*86YD(')E<&5T:71I=F4@=&5X="X*462463end464>>> "sheesh".encode('rot-13')465'furrfu'466```467468Для преобразования экземпляра класса в Unicode класс может определить метод `__unicode__()`, аналогичный [`__str__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__str__).469470`encode()`, `decode()` и `__unicode__()` были реализованы Марком-Андре Лембургом. Изменения для поддержки UCS-4 внутри были реализованы Фредриком Лундом и Мартином фон Лёвисом.471472> **См. также**473>474> **[**PEP 261**](https://python-all.ru/3.7/whatsnew/2.2.html) – Поддержка «широких» символов Unicode**475>476> Автор: Paul Prescod.477478## PEP 227: Вложенные области видимости479480В Python 2.1 статически вложенные области видимости были добавлены как опциональная возможность, которую нужно было включать директивой `from __future__ import nested_scopes`. В Python 2.2 вложенные области видимости больше не нужно специально включать; теперь они присутствуют всегда. Остальная часть этого раздела – копия описания вложенных областей видимости из моего документа «Что нового в Python 2.1»; если вы читали его, когда вышла версия 2.1, можете пропустить оставшуюся часть.481482Самое большое изменение, введённое в Python 2.1 и завершённое в 2.2, касается правил областей видимости Python. В Python 2.0 в любой момент времени для поиска имён переменных использовалось не более трёх пространств имён: локальное, модульное и встроенное. Это часто удивляло людей, потому что не соответствовало их интуитивным ожиданиям. Например, вложенное рекурсивное определение функции не работает:483484```python485def f():486 ...487 def g(value):488 ...489 return g(value-1) + 1490 ...491```492493Функция `g()` всегда будет вызывать исключение [`NameError`](https://python-all.ru/3.7/library/exceptions.html#NameError), потому что привязка имени `g` не находится ни в её локальном пространстве имён, ни в пространстве имён модуля. На практике это не такая уж большая проблема (подобные рекурсивные внутренние функции встречаются редко), но это также сделало использование выражения [`lambda`](https://python-all.ru/3.7/reference/expressions.html#lambda) более громоздким, и это было проблемой на практике. В коде, использующем `lambda`, часто можно встретить копирование локальных переменных путём передачи их в качестве значений аргументов по умолчанию.494495```python496def find(self, name):497 "Return list of any entries equal to 'name'"498 L = filter(lambda x, name=name: x == name,499 self.list_attribute)500 return L501```502503В результате удобочитаемость кода Python, написанного в сильно функциональном стиле, сильно страдает.504505Самое важное изменение в Python 2.2 – это добавление в язык статической области видимости для решения этой проблемы. Первый эффект: аргумент по умолчанию `name=name` теперь не нужен в приведённом выше примере. Проще говоря, если имя переменной не получает значение внутри функции (присваиванием, операторами [`def`](https://python-all.ru/3.7/reference/compound_stmts.html#def), [`class`](https://python-all.ru/3.7/reference/compound_stmts.html#class) или [`import`](https://python-all.ru/3.7/reference/simple_stmts.html#import)), ссылки на эту переменную будут искаться в локальном пространстве имён окружающей области видимости. Более подробное объяснение правил и разбор реализации можно найти в PEP.506507Это изменение может вызвать некоторые проблемы совместимости для кода, где одно и то же имя переменной используется как на уровне модуля, так и в качестве локальной переменной внутри функции, содержащей другие определения функций. Однако это кажется маловероятным, поскольку такой код и без того был бы довольно запутанным для чтения.508509Одним из побочных эффектов изменения является то, что операторы `from module import *` и `exec` стали недопустимыми в области видимости функции при определённых условиях. Справочное руководство Python всегда утверждало, что `from module import *` допустим только на верхнем уровне модуля, но интерпретатор CPython никогда раньше этого не соблюдал. В рамках реализации вложенных областей видимости компилятор, преобразующий исходный код Python в байт-код, должен генерировать разный код для доступа к переменным в охватывающей области видимости. `from module import *` и `exec` делают невозможным для компилятора определить это, поскольку они добавляют в локальное пространство имён имена, которые невозможно узнать на этапе компиляции. Поэтому, если функция содержит определения функций или выражения [`lambda`](https://python-all.ru/3.7/reference/expressions.html#lambda) со свободными переменными, компилятор укажет на это, вызвав исключение [`SyntaxError`](https://python-all.ru/3.7/library/exceptions.html#SyntaxError).510511Чтобы сделать предыдущее объяснение немного понятнее, вот пример:512513```python514x = 1515def f():516 # Следующая строка – синтаксическая ошибка517 exec 'x=2'518 def g():519 return x520```521522Строка 4, содержащая оператор `exec`, является синтаксической ошибкой, поскольку `exec` определил бы новую локальную переменную с именем `x`, значение которой должно быть доступно через `g()`.523524Это не должно быть большим ограничением, поскольку `exec` редко используется в большинстве кода Python (а когда используется, это часто признак плохого дизайна).525526> **См. также**527>528> **[**PEP 227**](https://python-all.ru/3.7/whatsnew/2.2.html) – Статически вложенные области видимости**529>530> Написан и реализован Джереми Хилтоном.531532## Новые и улучшенные модули533534- Модуль `xmlrpclib` был добавлен в стандартную библиотеку Фредриком Лундом; он предоставляет поддержку для написания XML-RPC клиентов. XML-RPC – это простой протокол удалённого вызова процедур, построенный на основе HTTP и XML. Например, следующий фрагмент получает список RSS-каналов от O’Reilly Network, а затем выводит последние заголовки для одного канала:535536 ```python537 import xmlrpclib538 s = xmlrpclib.Server(539 'http://www.oreillynet.com/meerkat/xml-rpc/server.php')540 channels = s.meerkat.getChannels()541 # channels – это список словарей, например:542 # [{'id': 4, 'title': 'Freshmeat Daily News'}543 # {'id': 190, 'title': '32Bits Online'},544 # {'id': 4549, 'title': '3DGamers'}, ... ]545546 # Получить элементы для одного канала547 items = s.meerkat.getItems( {'channel': 4} )548549 # 'items' – это ещё один список словарей, например:550 # [{'link': 'http://freshmeat.net/releases/52719/',551 # 'description': 'Утилита, которая преобразует HTML в XSL FO.',552 # {'title': 'html2fo 0.3 (По умолчанию)'}553 ```554555 Модуль `SimpleXMLRPCServer` упрощает создание простых XML-RPC серверов. Подробнее об XML-RPC см. [http://xmlrpc.scripting.com/](https://python-all.ru/3.7/whatsnew/2.2.html).556- Новый модуль [`hmac`](https://python-all.ru/3.7/library/hmac.html#module-hmac) реализует алгоритм HMAC, описанный в [**RFC 2104**](https://python-all.ru/3.7/whatsnew/2.2.html). (Автор: Gerhard Häring.)557- Некоторые функции, которые раньше возвращали длинные кортежи, теперь возвращают псевдопоследовательности, которые по-прежнему ведут себя как кортежи, но также имеют мнемонические атрибуты, такие как memberst\_mtime или `tm_year`. Улучшенные функции включают [`stat()`](https://python-all.ru/3.7/library/stat.html#module-stat), `fstat()`, `statvfs()` и `fstatvfs()` в модуле [`os`](https://python-all.ru/3.7/library/os.html#module-os), а также `localtime()`, `gmtime()` и `strptime()` в модуле [`time`](https://python-all.ru/3.7/library/time.html#module-time).558559 Например, чтобы получить размер файла с помощью старых кортежей, пришлось бы писать что-то вроде `file_size = os.stat(filename)[stat.ST_SIZE]`, но теперь это можно написать более наглядно как `file_size = os.stat(filename).st_size`.560561 Оригинальный патч для этой функции был предоставлен Ником Мэтьюсоном.562- Профилировщик Python был значительно переработан, и исправлены различные ошибки в его выводе. (Авторы: Фред Л. Дрейк-мл. и Тим Питерс.)563- Модуль [`socket`](https://python-all.ru/3.7/library/socket.html#module-socket) может быть скомпилирован с поддержкой IPv6; укажите опцию `--enable-ipv6` в скрипте configure Python. (Автор: Jun-ichiro “itojun” Hagino.)564- В модуль [`struct`](https://python-all.ru/3.7/library/struct.html#module-struct) добавлены два новых символа форматирования для 64-битных целых чисел на платформах, поддерживающих тип C `long long`. `q` предназначен для знакового 64-битного целого числа, а `Q` – для беззнакового. Значение возвращается в длинном целочисленном типе Python. (Автор: Tim Peters.)565- В интерактивном режиме интерпретатора появилась новая встроенная функция [`help()`](https://python-all.ru/3.7/library/functions.html#help), которая использует модуль [`pydoc`](https://python-all.ru/3.7/library/pydoc.html#module-pydoc), представленный в Python 2.1, для организации интерактивной справки. `help(object)` выводит любую доступную справку об *объекте*. [`help()`](https://python-all.ru/3.7/library/functions.html#help) без аргументов запускает утилиту онлайн-справки, где можно вводить имена функций, классов или модулей для чтения их справки. (Автор: Гвидо ван Россум, с использованием модуля Ka-Ping Yee [`pydoc`](https://python-all.ru/3.7/library/pydoc.html#module-pydoc).)566- В движок SRE, лежащий в основе модуля [`re`](https://python-all.ru/3.7/library/re.html#module-re), внесены различные исправления ошибок и улучшения производительности. Например, функции [`re.sub()`](https://python-all.ru/3.7/library/re.html#re.sub) и [`re.split()`](https://python-all.ru/3.7/library/re.html#re.split) были переписаны на C. Ещё один патч ускоряет некоторые диапазоны символов Unicode в два раза, а также появился новый `finditer()` метод, возвращающий итератор по всем непересекающимся совпадениям в заданной строке. (SRE поддерживается Фредриком Лундом. Патч BIGCHARSET предоставлен Мартином фон Лёвисом.)567- Модуль [`smtplib`](https://python-all.ru/3.7/library/smtplib.html#module-smtplib) теперь поддерживает [**RFC 2487**](https://python-all.ru/3.7/whatsnew/2.2.html), «Безопасный SMTP через TLS», так что теперь можно шифровать трафик SMTP между программой на Python и агентом передачи почты, которому передаётся сообщение. [`smtplib`](https://python-all.ru/3.7/library/smtplib.html#module-smtplib) также поддерживает аутентификацию SMTP. (Автор: Gerhard Häring.)568- Модуль [`imaplib`](https://python-all.ru/3.7/library/imaplib.html#module-imaplib), поддерживаемый Пирсом Лодером, получил поддержку нескольких новых расширений: расширение NAMESPACE, определённое в [**RFC 2342**](https://python-all.ru/3.7/whatsnew/2.2.html), SORT, GETACL и SETACL. (Авторы: Энтони Бакстер и Мишель Пеллетье.)569- Разбор адресов электронной почты в модуле `rfc822` теперь соответствует [**RFC 2822**](https://python-all.ru/3.7/whatsnew/2.2.html), обновлению [**RFC 822**](https://python-all.ru/3.7/whatsnew/2.2.html). (Имя модуля *не* будет изменено на `rfc2822`.) Также добавлен новый пакет, [`email`](https://python-all.ru/3.7/library/email.html#module-email), для разбора и создания сообщений электронной почты. (Автор: Барри Варшава, работа выросла из его работы над Mailman.)570- Модуль [`difflib`](https://python-all.ru/3.7/library/difflib.html#module-difflib) теперь содержит новый класс `Differ` для создания читаемых списков изменений («дельты») между двумя последовательностями строк текста. Также появились две функции-генератора, `ndiff()` и `restore()`, которые возвращают дельту из двух последовательностей или одну из исходных последовательностей из дельты. (Черновая работа выполнена Дэвидом Гуджером, на основе кода ndiff.py Тима Питерса, который затем выполнил генераторизацию.)571- Новые константы `ascii_letters`, `ascii_lowercase` и `ascii_uppercase` были добавлены в модуль [`string`](https://python-all.ru/3.7/library/string.html#module-string). Некоторые модули в стандартной библиотеке использовали `string.letters` для обозначения диапазонов A-Za-z, но это предположение неверно при использовании локалей, потому что `string.letters` изменяется в зависимости от набора допустимых символов, определённых текущей локалью. Все ошибочные модули были исправлены для использования `ascii_letters` вместо этого. (Сообщено неизвестным лицом; исправлено Фредом Л. Дрейком-мл.)572- Модуль [`mimetypes`](https://python-all.ru/3.7/library/mimetypes.html#module-mimetypes) теперь упрощает использование альтернативных баз данных MIME-типов за счёт добавления класса `MimeTypes`, который принимает список имён файлов для разбора. (Автор: Фред Л. Дрейк-мл.)573- Класс `Timer` был добавлен в модуль [`threading`](https://python-all.ru/3.7/library/threading.html#module-threading), который позволяет планировать выполнение действия в будущем. (Автор: Итамар Штуль-Трауринг.)574575## Изменения и исправления в интерпретаторе576577Некоторые изменения затрагивают только тех, кто работает с интерпретатором Python на уровне C, – тех, кто пишет модули расширения Python, встраивает интерпретатор или просто взламывает сам интерпретатор. Если вы пишете только код на Python, то описанные здесь изменения вас почти не затронут.578579- Функции профилирования и трассировки теперь могут быть реализованы на C, что позволяет работать гораздо быстрее, чем функции на Python, и должно снизить накладные расходы профилирования и трассировки. Это будет интересно авторам сред разработки для Python. В API Python были добавлены две новые функции на C, [`PyEval_SetProfile()`](https://python-all.ru/3.7/c-api/init.html#c.PyEval_SetProfile) и [`PyEval_SetTrace()`](https://python-all.ru/3.7/c-api/init.html#c.PyEval_SetTrace). Существующие функции [`sys.setprofile()`](https://python-all.ru/3.7/library/sys.html#sys.setprofile) и [`sys.settrace()`](https://python-all.ru/3.7/library/sys.html#sys.settrace) по-прежнему существуют и просто были изменены для использования нового интерфейса на уровне C. (Автор: Фред Л. Дрейк-мл.)580- Был добавлен ещё один низкоуровневый API, представляющий интерес в первую очередь для разработчиков отладчиков Python и инструментов разработки. [`PyInterpreterState_Head()`](https://python-all.ru/3.7/c-api/init.html#c.PyInterpreterState_Head) и [`PyInterpreterState_Next()`](https://python-all.ru/3.7/c-api/init.html#c.PyInterpreterState_Next) позволяют вызывающему коду просматривать все существующие объекты интерпретатора; [`PyInterpreterState_ThreadHead()`](https://python-all.ru/3.7/c-api/init.html#c.PyInterpreterState_ThreadHead) и [`PyThreadState_Next()`](https://python-all.ru/3.7/c-api/init.html#c.PyThreadState_Next) позволяют перебирать все состояния потоков для заданного интерпретатора. (Автор: Дэвид Бизли.)581- Интерфейс сборщика мусора на уровне C был изменён, чтобы упростить написание типов расширений, поддерживающих сборку мусора, и отладку неправильного использования функций. Различные функции получили немного другую семантику, поэтому ряд функций пришлось переименовать. Расширения, использующие старый API, по-прежнему будут компилироваться, но *не* будут участвовать в сборке мусора, поэтому их обновление для версии 2.2 следует считать довольно приоритетным.582583 Чтобы обновить модуль расширения до нового API, выполните следующие шаги:584- Переименуйте `Py_TPFLAGS_GC()` в `PyTPFLAGS_HAVE_GC()`.585- **Используйте [`PyObject_GC_New()`](https://python-all.ru/3.7/c-api/gcsupport.html#c.PyObject_GC_New) или [`PyObject_GC_NewVar()`](https://python-all.ru/3.7/c-api/gcsupport.html#c.PyObject_GC_NewVar) для выделения**586587 объектов, а [`PyObject_GC_Del()`](https://python-all.ru/3.7/c-api/gcsupport.html#c.PyObject_GC_Del) для их освобождения.588- **Переименовать `PyObject_GC_Init()` в [`PyObject_GC_Track()`](https://python-all.ru/3.7/c-api/gcsupport.html#c.PyObject_GC_Track) и**589590 `PyObject_GC_Fini()` в [`PyObject_GC_UnTrack()`](https://python-all.ru/3.7/c-api/gcsupport.html#c.PyObject_GC_UnTrack).591- Удалите `PyGC_HEAD_SIZE()` из расчётов размера объекта.592- Удалите вызовы `PyObject_AS_GC()` и `PyObject_FROM_GC()`.593- Новая форматная последовательность `et` была добавлена в [`PyArg_ParseTuple()`](https://python-all.ru/3.7/c-api/arg.html#c.PyArg_ParseTuple); `et` принимает как параметр, так и имя кодировки, и преобразует параметр в заданную кодировку, если параметр оказывается строкой Unicode, или оставляет его без изменений, если это 8-битная строка, предполагая, что она уже находится в нужной кодировке. Это отличается от символа формата `es`, который предполагает, что 8-битные строки находятся в кодировке ASCII по умолчанию в Python, и преобразует их в указанную новую кодировку. (Автор: М.-А. Лембург; используется для поддержки MBCS в Windows, описанной в следующем разделе.)594- Добавлена другая функция разбора аргументов, [`PyArg_UnpackTuple()`](https://python-all.ru/3.7/c-api/arg.html#c.PyArg_UnpackTuple), которая проще и, предположительно, быстрее. Вместо указания строки формата вызывающий просто задаёт минимальное и максимальное ожидаемое количество аргументов, а также набор указателей на переменные [`PyObject*`](https://python-all.ru/3.7/c-api/structures.html#c.PyObject), которые будут заполнены значениями аргументов.595- В таблицах определений методов доступны два новых флага [`METH_NOARGS`](https://python-all.ru/3.7/c-api/structures.html#METH_NOARGS) и [`METH_O`](https://python-all.ru/3.7/c-api/structures.html#METH_O), упрощающие реализацию методов без аргументов или с одним нетипизированным аргументом. Вызов таких методов эффективнее, чем вызов соответствующего метода, использующего [`METH_VARARGS`](https://python-all.ru/3.7/c-api/structures.html#METH_VARARGS). Кроме того, старый стиль написания методов на C `METH_OLDARGS` теперь официально устарел.596- Добавлены две новые функции-обёртки [`PyOS_snprintf()`](https://python-all.ru/3.7/c-api/conversion.html#c.PyOS_snprintf) и [`PyOS_vsnprintf()`](https://python-all.ru/3.7/c-api/conversion.html#c.PyOS_vsnprintf), предоставляющие кроссплатформенные реализации для относительно новых API библиотеки C `snprintf()` и `vsnprintf()`. В отличие от стандартных функций `sprintf()` и `vsprintf()`, версии Python проверяют границы используемого буфера для защиты от переполнения буфера. (Автор: M.-A. Lemburg.)597- Функция [`_PyTuple_Resize()`](https://python-all.ru/3.7/c-api/tuple.html#c._PyTuple_Resize) лишилась неиспользуемого параметра, так что теперь она принимает 2 параметра вместо 3. Третий аргумент никогда не использовался, и при переносе кода с более ранних версий на Python 2.2 его можно просто отбросить.598599## Другие изменения и исправления600601Как обычно, было множество других улучшений и исправлений ошибок, разбросанных по всему дереву исходного кода. Поиск по журналам изменений CVS показывает, что между Python 2.1 и 2.2 было применено 527 патчей и исправлено 683 ошибки; в 2.2.1 применено 139 патчей и исправлено 143 ошибки; в 2.2.2 применено 106 патчей и исправлено 82 ошибки. Эти цифры, вероятно, занижены.602603Некоторые из наиболее заметных изменений:604605- Код порта Python для MacOS, поддерживаемый Джеком Янсеном, теперь хранится в главном дереве CVS Python, и было внесено много изменений для поддержки MacOS X.606607 Самое значительное изменение – возможность собрать Python в виде фреймворка, включаемая указанием опции `--enable-framework` скрипту configure при компиляции Python. По словам Джека Янсена, «Это устанавливает самодостаточную установку Python вместе с «клеем» фреймворка OS X в `/Library/Frameworks/Python.framework` (или другое место по выбору). Пока что от этого мало непосредственной пользы (на самом деле есть недостаток: нужно изменить PATH, чтобы найти Python), но это основа для создания полноценного приложения Python, портирования MacPython IDE, возможного использования Python в качестве стандартного скриптового языка OSA и многого другого».608609 Большинство модулей инструментария MacPython, которые взаимодействуют с API MacOS, такими как оконная система, QuickTime, скриптинг и т.д., были портированы на OS X, но оставлены закомментированными в `setup.py`. Желающие поэкспериментировать с этими модулями могут раскомментировать их вручную.610- Передача именованных аргументов встроенным функциям, которые их не принимают, теперь вызывает исключение [`TypeError`](https://python-all.ru/3.7/library/exceptions.html#TypeError) с сообщением «*функция* не принимает именованных аргументов».611- Слабые ссылки, добавленные в Python 2.1 как модуль расширения, теперь являются частью ядра, поскольку они используются в реализации классов нового стиля. Исключение [`ReferenceError`](https://python-all.ru/3.7/library/exceptions.html#ReferenceError) соответственно перемещено из модуля [`weakref`](https://python-all.ru/3.7/library/weakref.html#module-weakref) и стало встроенным исключением.612- Новый скрипт `Tools/scripts/cleanfuture.py` от Тима Питерса автоматически удаляет устаревшие операторы `__future__` из исходного кода Python.613- Во встроенную функцию [`compile()`](https://python-all.ru/3.7/library/functions.html#compile) добавлен дополнительный аргумент *flags*, так что теперь поведение операторов `__future__` можно корректно наблюдать в симулированных оболочках, например в IDLE и других средах разработки. Это описано в [**PEP 264**](https://python-all.ru/3.7/whatsnew/2.2.html). (Автор: Michael Hudson.)614- Новая лицензия, введённая в Python 1.6, не была совместима с GPL. Это исправлено небольшими текстовыми изменениями в лицензии 2.2, так что теперь снова разрешено встраивать Python в программы под GPL. Обратите внимание, что сам Python не под GPL, а распространяется по лицензии, по существу эквивалентной лицензии BSD, как и раньше. Изменения лицензии также были применены к релизам Python 2.0.1 и 2.1.1.615- При получении имени файла в Unicode на Windows Python теперь преобразует его в строку в кодировке MBCS, как используется API файлов Microsoft. Поскольку API файлов явно используют MBCS, выбор Python в пользу ASCII в качестве кодировки по умолчанию оказывается неудобным. На Unix используется набор символов локали, если доступен `locale.nl_langinfo(CODESET)`. (Поддержка Windows предоставлена Марком Хаммондом при содействии Марка-Андре Лембурга. Поддержка Unix добавлена Мартином фон Лёвисом.)616- Поддержка больших файлов теперь включена на Windows. (Автор: Tim Peters.)617- Скрипт `Tools/scripts/ftpmirror.py` теперь анализирует файл `.netrc`, если он есть. (Автор: Mike Romberg.)618- Некоторые возможности объекта, возвращаемого функцией `xrange()`, теперь устарели и вызывают предупреждения при обращении к ним; они исчезнут в Python 2.3. Объекты `xrange` пытались притворяться полноценными последовательностями, поддерживая срезы, умножение последовательностей и оператор [`in`](https://python-all.ru/3.7/reference/expressions.html#in), но эти возможности редко использовались и поэтому были ошибочными. Метод `tolist()` и атрибуты `start`, `stop`, `step` также устаревают. На уровне C четвёртый аргумент функции `PyRange_New()`, `repeat`, также устарел.619- Было множество патчей к реализации словарей, в основном для исправления потенциальных дампов ядра, если словарь содержит объекты, которые хитро изменили своё хеш-значение или изменили сам словарь, в котором содержались. Некоторое время python-dev вошёл в плавный ритм: Майкл Хадсон находил случай, приводящий к дампу ядра, Тим Питерс исправлял ошибку, Майкл находил другой случай, и так по кругу.620- На Windows Python теперь можно скомпилировать с помощью Borland C благодаря ряду патчей, предоставленных Стивеном Хансеном, хотя результат пока не полностью функционален. (Но это *есть* прогресс…)621- Ещё одно улучшение Windows: компания Wise Solutions щедро предоставила PythonLabs возможность использовать их систему InstallerMaster 8.1. Ранние инсталляторы PythonLabs для Windows использовали Wise 5.0a, который уже начинал показывать свой возраст. (Упаковано Тимом Питерсом.)622- Файлы, оканчивающиеся на `.pyw`, теперь можно импортировать в Windows. `.pyw` – это специфичное для Windows обозначение, используемое для указания, что скрипт должен запускаться с помощью PYTHONW.EXE вместо PYTHON.EXE, чтобы не появлялась консоль DOS для вывода. Этот патч позволяет импортировать такие скрипты, если они также могут использоваться как модули. (Реализовано Дэвидом Боленом.)623- На платформах, где Python использует функцию C `dlopen()` для загрузки модулей расширения, теперь можно задавать флаги, используемые `dlopen()`, с помощью функций [`sys.getdlopenflags()`](https://python-all.ru/3.7/library/sys.html#sys.getdlopenflags) и [`sys.setdlopenflags()`](https://python-all.ru/3.7/library/sys.html#sys.setdlopenflags). (Автор: Bram Stolk.)624- Встроенная функция [`pow()`](https://python-all.ru/3.7/library/functions.html#pow) больше не поддерживает 3 аргумента, когда передаются числа с плавающей запятой. `pow(x, y, z)` возвращает `(x**y) % z`, но это никогда не бывает полезным для чисел с плавающей запятой, и конечный результат непредсказуемо варьируется в зависимости от платформы. Вызов вида `pow(2.0, 8.0, 7.0)` теперь вызовет исключение [`TypeError`](https://python-all.ru/3.7/library/exceptions.html#TypeError).625626## Благодарности627628Автор хотел бы поблагодарить следующих людей за предложения, исправления и помощь с различными черновиками этой статьи: Фред Бреммер, Кейт Бриггс, Эндрю Далк, Фред Л. Дрейк-младший, Карел Феллингер, Дэвид Гуджер, Марк Хаммонд, Стивен Хансен, Майкл Хадсон, Джек Янсен, Марк-Андре Лембург, Мартин фон Лёвис, Фредрик Лунд, Майкл МакЛей, Ник Мэтьюсон, Пол Мур, Густаво Нимейер, Дон О’Доннелл, Юнас Пааласма, Тим Питерс, Йенс Кваде, Том Рейнхардт, Нил Шеменауэр, Гвидо ван Россум, Грег Уорд, Эдвард Уэлборн.629