Документация Python неофициальный перевод
Содержание страницы

Что нового в Python 2.2What’s New in Python 2.2

Автор:A.M. Kuchling

ВведениеIntroduction

Эта статья объясняет новые возможности Python 2.2.2, выпущенного 14 октября 2002 года. Python 2.2.2 – это выпуск с исправлением ошибок Python 2.2, первоначально вышедшего 21 декабря 2001 года.

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

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

См. также

http://www.unixreview.com/documents/s=1356/urm0109h/0109h.htm
Статья «What’s So Special About Python 2.2?» тоже рассказывает о новых возможностях 2.2 и была написана Кэмероном Лэрдом и Кэтрин Сорайз.

PEP 252 и 253: Изменения типов и классовPEPs 252 and 253: Type and Class Changes

Самые большие и далеко идущие изменения в Python 2.2 касаются модели объектов и классов. Изменения должны быть обратно совместимы, поэтому ваш код, скорее всего, продолжит работать без изменений, но эти изменения дают потрясающие новые возможности. Перед тем как приступить к самому длинному и сложному разделу этой статьи, я дам обзор изменений и выскажу несколько замечаний.

Давным-давно я написал веб-страницу (http://www.amk.ca/python/writing/warts.html), перечисляющую недостатки дизайна Python. Одним из самых существенных недостатков была невозможность наследовать типы Python, реализованные на C. В частности, невозможно наследовать встроенные типы, поэтому нельзя, скажем, просто унаследовать список, чтобы добавить к нему один полезный метод. Модуль UserList предоставляет класс, поддерживающий все методы списков, от которого можно наследовать дальше, но множество кода на C ожидает обычный список Python и не принимает экземпляр UserList.

Python 2.2 исправляет это, и в процессе добавляет несколько захватывающих новых возможностей. Краткое резюме:

  • Вы можете наследовать встроенные типы, такие как списки и даже целые числа, и ваши подклассы должны работать везде, где требуется исходный тип.
  • Теперь можно определять статические методы и методы класса, в дополнение к методам экземпляра, доступным в предыдущих версиях Python.
  • Также появилась возможность автоматически вызывать методы при доступе или установке атрибута экземпляра с помощью нового механизма, называемого свойствами. Многие случаи использования __getattr__() можно переписать с использованием свойств, что сделает код проще и быстрее. В качестве небольшого дополнительного преимущества у атрибутов теперь тоже могут быть строки документации.
  • Список допустимых атрибутов экземпляра можно ограничить определённым набором с помощью слотов, что позволяет защититься от опечаток и, возможно, сделать больше оптимизаций в будущих версиях Python.

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

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

Я не буду пытаться охватить каждый частный случай и мелкое изменение, необходимые для работы новых функций. Вместо этого данный раздел опишет только общую картину. Смотрите раздел Связанные ссылки, «Связанные ссылки», для получения дополнительных источников информации о новой объектной модели Python 2.2.

Старые и новые классыOld and New Classes

Прежде всего, следует знать, что Python 2.2 действительно имеет два вида классов: классические (или старые) классы и классы нового стиля. Модель старых классов в точности такая же, как в более ранних версиях Python. Все новые возможности, описанные в этом разделе, применимы только к классам нового стиля. Это разделение не предполагается сохранять навсегда; в конечном итоге старые классы будут удалены, возможно, в Python 3.0.

Итак, как определить класс нового стиля? Наследованием от существующего класса нового стиля. Большинство встроенных типов Python, такие как целые числа, списки, словари и даже файлы, теперь являются классами нового стиля. Класс нового стиля с именем object, базовый класс для всех встроенных типов, также был добавлен, так что если ни один встроенный тип не подходит, можно просто унаследоваться от object:

class C(object):
    def __init__ (self):
        ...
    ...

Это означает, что операторы class, не имеющие базовых классов, в Python 2.2 всегда являются классическими классами. (На самом деле это можно изменить, установив переменную уровня модуля с именем __metaclass__ – см. PEP 253 для подробностей – но проще просто унаследоваться от object.)

Объекты типов для встроенных типов доступны как встроенные объекты, названные с помощью хитроумного трюка. В Python всегда были встроенные функции с именами int(), float() и str(). В версии 2.2 они больше не функции, а объекты типов, которые ведут себя как фабрики при вызове.

>>> int
<type 'int'>
>>> int('123')
123

Чтобы сделать набор типов полным, были добавлены новые объекты типов, такие как dict() и file(). Вот более интересный пример: добавление метода lock() к объектам файла:

class LockableFile(file):
    def lock (self, operation, length=0, start=0, whence=0):
        import fcntl
        return fcntl.lockf(self.fileno(), operation,
                           length, start, whence)

Теперь устаревший модуль posixfile содержал класс, который эмулировал все методы файлового объекта и добавлял метод lock(), но этот класс нельзя было передать внутренним функциям, ожидающим встроенный файл, что возможно с нашим новым LockableFile.

ДескрипторыDescriptors

В предыдущих версиях Python не было единого способа узнать, какие атрибуты и методы поддерживаются объектом. Существовали некоторые неформальные соглашения, например, определение атрибутов __members__ и __methods__, которые были списками имён, но часто автор типа расширения или класса не утруждал себя их определением. Можно было прибегнуть к проверке __dict__ объекта, но при использовании наследования классов или произвольного хука __getattr__() это всё равно могло быть неточным.

Одна большая идея, лежащая в основе новой модели классов, заключается в формализации API для описания атрибутов объекта с помощью дескрипторов. Дескрипторы определяют значение атрибута, указывая, является ли он методом или полем. Благодаря API дескрипторов становятся возможными статические методы, методы класса, а также более экзотические конструкции.

Дескрипторы атрибутов – это объекты, которые находятся внутри объектов классов и имеют несколько собственных атрибутов:

  • __name__ – это имя атрибута.
  • __doc__ – это строка документации атрибута.
  • __get__(object)() – это метод, который извлекает значение атрибута из object.
  • __set__(object, value)() устанавливает атрибут object в значение value.
  • __delete__(object, value)() удаляет атрибут value объекта object.

Например, когда вы пишете obj.x, Python на самом деле выполняет следующие шаги:

descriptor = obj.__class__.x
descriptor.__get__(obj)

Для методов descriptor.__get__() возвращает временный вызываемый объект, который оборачивает экземпляр и вызываемый метод. Именно поэтому теперь возможны статические методы и методы класса; у них есть дескрипторы, которые оборачивают только метод или метод и класс. Вкратце объясняя эти новые виды методов: статические методы не получают экземпляр и поэтому напоминают обычные функции. Методы класса получают класс объекта, но не сам объект. Статические методы и методы класса определяются так:

class C(object):
    def f(arg1, arg2):
        ...
    f = staticmethod(f)

    def g(cls, arg1, arg2):
        ...
    g = classmethod(g)

Функция staticmethod() принимает функцию f() и возвращает её, обёрнутую в дескриптор, чтобы её можно было сохранить в объекте класса. Можно было бы ожидать специальный синтаксис для создания таких методов (def static f, defstatic f() или что-то в этом роде), но такого синтаксиса ещё не определили; это оставлено для будущих версий Python.

Многие новые возможности, такие как слоты (slots) и свойства (properties), также реализованы как новые виды дескрипторов, и написать класс дескриптора, делающий что-то новое, несложно. Например, можно написать класс дескриптора, который позволяет записывать предусловия и постусловия в стиле языка Eiffel для метода. Класс, использующий эту возможность, может быть определён следующим образом:

from eiffel import eiffelmethod

class C(object):
    def f(self, arg1, arg2):
        # Собственно функция
        ...
    def pre_f(self):
        # Проверить предусловия
        ...
    def post_f(self):
        # Проверить постусловия
        ...

    f = eiffelmethod(f, pre_f, post_f)

Обратите внимание, что человек, использующий новый eiffelmethod(), не обязан ничего понимать в дескрипторах. Именно поэтому я считаю, что новые возможности не увеличивают базовую сложность языка. Найдётся несколько волшебников, которым нужно будет знать о них, чтобы написать eiffelmethod() или ZODB или что-то ещё, но большинство пользователей просто будут писать код поверх полученных библиотек и не обращать внимания на детали реализации.

Множественное наследование: правило ромбаMultiple Inheritance: The Diamond Rule

Множественное наследование стало более полезным благодаря изменению правил разрешения имён. Рассмотрим следующий набор классов (диаграмма взята из PEP 253 Гвидо ван Россума):

      class A:
        ^ ^  def save(self): ...
       /   \
      /     \
     /       \
    /         \
class B     class C:
    ^         ^  def save(self): ...
     \       /
      \     /
       \   /
        \ /
      class D

Правило поиска для классических классов простое, но не очень умное; базовые классы просматриваются в глубину, слева направо. Ссылка на D.save() будет искать в классах D, B, а затем A, где будет найден save() и возвращён. C.save() никогда не будет найден. Это плохо, потому что если метод C's save() сохраняет некоторое внутреннее состояние, специфичное для C, то его невызов приведёт к тому, что это состояние никогда не будет сохранено.

Классы нового стиля следуют другому алгоритму, который немного сложнее объяснить, но делает правильное дело в этой ситуации. (Обратите внимание, что Python 2.3 изменяет этот алгоритм на тот, который в большинстве случаев даёт те же результаты, но даёт более полезные результаты для действительно сложных графов наследования.)

  1. Перечислить все базовые классы, следуя классическому правилу поиска, и включать класс несколько раз, если он посещается повторно. В приведённом выше примере список посещённых классов – [D, B, A, C, A].
  2. Просмотреть список на предмет дублирующихся классов. Если таковые найдены, удалить все вхождения, кроме одного, оставив в списке последнее. В приведённом выше примере после удаления дубликатов список становится [D, B, C, A].

Следуя этому правилу, обращение к D.save() вернёт C.save(), что и является требуемым поведением. Это правило поиска такое же, как в Common Lisp. Новая встроенная функция super() позволяет получить доступ к суперклассам класса без необходимости переопределять алгоритм Python. Наиболее часто используемая форма – super(class, obj)(), которая возвращает связанный объект суперкласса (не сам объект класса). Эта форма будет использоваться в методах для вызова метода суперкласса; например, метод D.save() будет выглядеть так:

class D (B,C):
    def save (self):
        # Вызвать .save() родительского класса
        super(D, self).save()
        # Сохранить приватные данные D здесь
        ...

super() также может возвращать несвязанные объекты суперкласса при вызове в виде super(class)() или super(class1, class2)(), но это, вероятно, не будет часто полезно.

Доступ к атрибутамAttribute Access

Довольно много сложных классов Python определяют хуки для доступа к атрибутам с помощью __getattr__(); чаще всего это делается для удобства, чтобы сделать код более читаемым, автоматически отображая доступ к атрибуту, такой как obj.parent, на вызов метода, например obj.get_parent. Python 2.2 добавляет несколько новых способов управления доступом к атрибутам.

Во-первых, __getattr__(attr_name)() по-прежнему поддерживается классами нового стиля, и ничего в нём не изменилось. Как и раньше, он будет вызываться при попытке доступа к obj.foo, если атрибут с именем foo не найден в словаре экземпляра.

Классы нового стиля также поддерживают новый метод, __getattribute__(attr_name)(). Разница между этими двумя методами в том, что __getattribute__() вызывается всегда при доступе к любому атрибуту, тогда как старый __getattr__() вызывается только в том случае, если foo не найден в словаре экземпляра.

Однако поддержка свойств в Python 2.2 часто будет более простым способом перехвата ссылок на атрибуты. Написание метода __getattr__() усложнено, потому что для избежания рекурсии внутри него нельзя использовать обычные обращения к атрибутам, и вместо этого приходится возиться с содержимым __dict__. Методы __getattr__() также в конечном итоге вызываются Python, когда он проверяет другие методы, такие как __repr__() или __coerce__(), и поэтому их нужно писать с учётом этого. Наконец, вызов функции при каждом доступе к атрибуту приводит к значительной потере производительности.

property – это новый встроенный тип, который объединяет три функции: получение, установку или удаление атрибута, а также строку документации. Например, если вы хотите определить атрибут size, который вычисляется, но также может быть установлен, можно написать:

class C(object):
    def get_size (self):
        result = ... computation ...
        return result
    def set_size (self, size):
        ... compute something based on the size
        and set internal state appropriately ...

    # Определить свойство. Метод 'delete this attribute'
    # метод определён как None, поэтому атрибут
    # не может быть удалён.
    size = property(get_size, set_size,
                    None,
                    "Storage size of this instance")

Это определённо понятнее и проще в написании, чем пара методов __getattr__()/__setattr__(), которые проверяют атрибут size и обрабатывают его особым образом, извлекая все остальные атрибуты из __dict__ экземпляра. Обращения к size – единственные, которые требуют вызова функции, поэтому ссылки на другие атрибуты выполняются с обычной скоростью.

Наконец, можно ограничить список атрибутов, на которые можно ссылаться в объекте, с помощью нового атрибута класса __slots__. Объекты Python обычно очень динамичны; в любой момент можно определить новый атрибут экземпляра, просто написав obj.new_attr=1. Класс нового стиля может определить атрибут класса с именем __slots__, чтобы ограничить допустимые атрибуты определённым набором имён. Пример прояснит это:

>>> class C(object):
...     __slots__ = ('template', 'name')
...
>>> obj = C()
>>> print obj.template
None
>>> obj.template = 'Test'
>>> print obj.template
Test
>>> obj.newattr = None
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: 'C' object has no attribute 'newattr'

Обратите внимание, как при попытке присвоить атрибуту, не указанному в __slots__, возникает AttributeError.

PEP 234: ИтераторыPEP 234: Iterators

Ещё одно значительное дополнение в 2.2 – это интерфейс итерации на уровнях C и Python. Объекты могут определять, как по ним можно итерироваться вызывающим кодом.

В версиях Python до 2.1 обычным способом заставить работать for item in obj было определение метода __getitem__(), который выглядел примерно так:

def __getitem__(self, index):
    return <next item>

__getitem__() правильнее использовать для определения операции индексации над объектом, чтобы можно было писать obj[5] для получения шестого элемента. Это немного вводит в заблуждение, когда вы используете его только для поддержки циклов for. Рассмотрим некий файлоподобный объект, который предполагается перебирать в цикле; параметр index по сути бессмыслен, так как класс, вероятно, предполагает, что будет серия вызовов __getitem__() с index, каждый раз увеличивающимся на единицу. Другими словами, наличие метода __getitem__() не означает, что использование file[5] для произвольного доступа к шестому элементу сработает, хотя по идее должно.

В Python 2.2 итерация может быть реализована отдельно, и методы __getitem__() могут быть ограничены классами, которые действительно поддерживают произвольный доступ. Основная идея итераторов проста. Новая встроенная функция iter(obj)() или iter(C, sentinel) используется для получения итератора. iter(obj)() возвращает итератор для объекта obj, тогда как iter(C, sentinel) возвращает итератор, который будет вызывать вызываемый объект C до тех пор, пока он не вернёт sentinel, сигнализируя о завершении итератора.

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

Итак, что же на самом деле делают итераторы? У них есть один обязательный метод next(), который не принимает аргументов и возвращает следующее значение. Когда больше нечего возвращать, вызов next() должен вызывать исключение StopIteration.

>>> L = [1,2,3]
>>> i = iter(L)
>>> print i
<iterator object at 0x8116870>
>>> i.next()
1
>>> i.next()
2
>>> i.next()
3
>>> i.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
StopIteration
>>>

В версии 2.2 оператор for в Python больше не ожидает последовательность; он ожидает что-то, для чего iter() вернёт итератор. Для обратной совместимости и удобства итератор автоматически создаётся для последовательностей, которые не реализуют __iter__() или слот tp_iter, так что for i in [1,2,3] по-прежнему будет работать. Везде, где интерпретатор Python перебирает последовательность, он был изменён для использования протокола итераторов. Это означает, что можно делать такие вещи, как:

>>> L = [1,2,3]
>>> i = iter(L)
>>> a,b,c = i
>>> a,b,c
(1, 2, 3)

Поддержка итераторов была добавлена для некоторых базовых типов Python. Вызов iter() на словаре вернёт итератор, который перебирает его ключи:

>>> m = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
...      'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12}
>>> for key in m: print key, m[key]
...
Mar 3
Feb 2
Aug 8
Sep 9
May 5
Jun 6
Jul 7
Jan 1
Apr 4
Nov 11
Dec 12
Oct 10

Это лишь поведение по умолчанию. Если требуется перебирать ключи, значения или пары ключ/значение, можно явно вызвать методы iterkeys(), itervalues() или iteritems(), чтобы получить соответствующий итератор. В небольшом сопутствующем изменении оператор in теперь работает со словарями, так что key in dict теперь эквивалентно dict.has_key(key).

Файлы также предоставляют итератор, который вызывает метод readline(), пока в файле не останется строк. Это значит, что теперь можно читать каждую строку файла с помощью такого кода:

for line in file:
    # сделать что-то для каждой строки
    ...

Обратите внимание, что по итератору можно двигаться только вперёд; нет способа получить предыдущий элемент, сбросить итератор или сделать его копию. Объект-итератор может предоставлять такие дополнительные возможности, но протокол итераторов требует только метод next().

См. также

PEP 234 – Итераторы
Авторы: Ка-Пинг Йи и Гвидо ван Россум; реализовано командой Python Labs, в основном Гвидо и Тимом Петерсом.

PEP 255: Простые генераторыPEP 255: Simple Generators

Генераторы – ещё одна новая возможность, которая связана с введением итераторов.

Вы, несомненно, знакомы с тем, как работают вызовы функций в Python или C. Когда вы вызываете функцию, она получает частное пространство имён, в котором создаются её локальные переменные. Когда функция доходит до оператора return, локальные переменные уничтожаются, а полученное значение возвращается вызывающему. Последующий вызов той же функции получит новый набор локальных переменных. Но что, если бы локальные переменные не уничтожались при выходе из функции? Что, если бы можно было позже возобновить функцию с того места, где она остановилась? Именно это и обеспечивают генераторы; их можно рассматривать как возобновляемые функции.

Вот простейший пример функции-генератора:

def generate_ints(N):
    for i in range(N):
        yield i

Для генераторов было введено новое ключевое слово yield. Любая функция, содержащая оператор yield, является генераторной; это обнаруживается компилятором байт-кода Python, который соответствующим образом компилирует функцию. Из-за введения нового ключевого слова генераторы должны быть явно включены в модуле путём включения оператора from __future__ import generators в начале исходного кода модуля. В Python 2.3 этот оператор станет ненужным.

Когда вы вызываете генераторную функцию, она возвращает не одно значение, а объект-генератор, который поддерживает протокол итераторов. При выполнении оператора yield генератор выводит значение i, аналогично оператору return. Большая разница между yield и оператором return заключается в том, что при достижении yield состояние выполнения генератора приостанавливается, а локальные переменные сохраняются. При следующем вызове метода next() генератора функция возобновит выполнение сразу после оператора yield. (По сложным причинам оператор yield не допускается внутри блока try оператора try...finally; прочтите PEP 255 для полного объяснения взаимодействия между yield и исключениями.)

Вот пример использования генератора generate_ints():

>>> gen = generate_ints(3)
>>> gen
<generator object at 0x8117f90>
>>> gen.next()
0
>>> gen.next()
1
>>> gen.next()
2
>>> gen.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 2, in generate_ints
StopIteration

Можно также написать for i in generate_ints(5), или a,b,c = generate_ints(3).

Внутри генераторной функции оператор return может использоваться только без значения и сигнализирует об окончании выдачи значений; после этого генератор не может вернуть больше значений. return со значением, например return 5, является синтаксической ошибкой внутри генераторной функции. Окончание результатов генератора также можно указать, возбудив StopIteration вручную или просто позволив потоку выполнения достичь конца функции.

Эффекта генераторов можно добиться вручную, написав собственный класс и сохранив все локальные переменные генератора как атрибуты экземпляра. Например, возврат списка целых чисел можно сделать, установив self.count в 0 и заставив метод next() увеличивать self.count и возвращать его. Однако для сколько-нибудь сложного генератора написание соответствующего класса было бы гораздо запутаннее. Lib/test/test_generators.py содержит ряд более интересных примеров. Простейший из них реализует обход дерева в порядке (in-order) с использованием генераторов рекурсивно.

# Рекурсивный генератор, порождающий листья дерева в порядке in-order.
def inorder(t):
    if t:
        for x in inorder(t.left):
            yield x
        yield t.label
        for x in inorder(t.right):
            yield x

Два других примера в Lib/test/test_generators.py дают решения задачи о N ферзях (размещение $N$ ферзей на доске $N \times N$ так, чтобы ни один ферзь не угрожал другому) и задачи о ходе коня (маршрут, который проводит коня через каждую клетку доски $N \times N$, не посещая ни одну клетку дважды).

Идея генераторов пришла из других языков программирования, особенно Icon (http://www.cs.arizona.edu/icon/), где идея генераторов является центральной. В Icon каждое выражение и вызов функции ведут себя как генератор. Один пример из «An Overview of the Icon Programming Language» по адресу http://www.cs.arizona.edu/icon/docs/ipd266.htm даёт представление о том, как это выглядит:

sentence := "Store it in the neighboring harbor"
if (i := find("or", sentence)) > 5 then write(i)

В Icon функция find() возвращает индексы, по которым встречается подстрока «or»: 3, 23, 33. В операторе if i сначала присваивается значение 3, но 3 меньше 5, поэтому сравнение не проходит, и Icon повторяет его со вторым значением 23. 23 больше 5, поэтому сравнение теперь успешно, и код выводит значение 23 на экран.

Python не заходит так далеко, как Icon, в принятии генераторов в качестве центральной концепции. Генераторы считаются новой частью ядра языка Python, но их изучение или использование не является обязательным; если они не решают ваших задач, можете их игнорировать. Одной из новых особенностей интерфейса Python по сравнению с Icon является то, что состояние генератора представляется как конкретный объект (итератор), который можно передавать другим функциям или хранить в структуре данных.

См. также

PEP 255 - Simple Generators
Авторы: Нил Шеменауэр, Тим Питерс, Магнус Ли Хетланд. Реализовано в основном Нилом Шеменауэром и Тимом Питерсом, с дополнительными исправлениями от команды Python Labs.

PEP 237: Унификация длинных целых и целых чиселPEP 237: Unifying Long Integers and Integers

В последних версиях различие между обычными целыми числами (32-битные значения на большинстве машин) и длинными целыми числами (произвольного размера) становилось раздражающим. Например, на платформах, поддерживающих файлы размером более 2**32 байт, метод tell() файловых объектов должен возвращать длинное целое. Однако в некоторых частях Python ожидались обычные целые числа, и при передаче длинного целого возникала ошибка. Например, в Python 1.5 только обычные целые можно было использовать в качестве индекса среза, и 'abc'[1L:] вызывало исключение TypeError с сообщением «slice index must be int».

Python 2.2 будет преобразовывать значения из коротких целых в длинные по мере необходимости. Суффикс «L» больше не нужен для обозначения литерала длинного целого, так как теперь компилятор сам выберет подходящий тип. (Использование суффикса «L» будет не рекомендоваться в будущих версиях Python 2.x, вызывая предупреждение в Python 2.4 и, вероятно, будет удалено в Python 3.0.) Многие операции, которые раньше вызывали OverflowError, теперь будут возвращать длинное целое в качестве результата. Например:

>>> 1234567890123
1234567890123L
>>> 2 ** 64
18446744073709551616L

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

См. также

PEP 237 – Унификация длинных целых и целых чисел
Авторы: Моше Задка и Гвидо ван Россум. В основном реализовано Гвидо ван Россумом.

PEP 238: Изменение оператора деленияPEP 238: Changing the Division Operator

Самое противоречивое изменение в Python 2.2 знаменует начало усилий по исправлению старого проектного недостатка, существовавшего в Python с самого начала. В настоящее время оператор деления Python, /, ведёт себя как оператор деления в C, когда оба операнда целые: он возвращает целочисленный результат, усечённый вниз при наличии дробной части. Например, 3/2 равно 1, а не 1,5, и (-1)/2 равно -1, а не -0,5. Это означает, что результаты деления могут неожиданно различаться в зависимости от типа двух операндов, а из-за динамической типизации Python бывает трудно определить возможные типы операндов.

(Спор заключается в том, является ли это действительно ошибкой проектирования и стоит ли ломать существующий код для её исправления. Это вызвало бесконечные обсуждения в python-dev, а в июле 2001 года вылилось в шквал едко-саркастических сообщений в comp.lang.python. Я не буду выступать ни на одной стороне и ограничусь описанием того, что реализовано в 2.2. Прочтите PEP 238 для сводки аргументов и контраргументов.)

Поскольку это изменение может нарушить работу существующего кода, его внедряют очень постепенно. Переход начинается в Python 2.2, но полное переключение произойдёт только в Python 3.0.

Сначала я позаимствую несколько терминов из PEP 238. «Истинное деление» – это деление, знакомое большинству не-программистов: 3/2 равно 1,5, 1/4 равно 0,25 и так далее. «Деление с округлением вниз» (floor division) – это то, что оператор / в Python сейчас делает с целочисленными операндами; результат – это округлённое вниз значение, возвращаемое истинным делением. «Классическое деление» – это текущее смешанное поведение /; оно возвращает результат деления с округлением вниз, когда операнды – целые числа, и результат истинного деления, когда один из операндов – число с плавающей запятой.

Вот изменения, которые вводит Python 2.2:

  • Новый оператор // – это оператор деления с округлением вниз. (Да, мы знаем, что он похож на символ комментария в C++.) // всегда выполняет деление с округлением вниз независимо от типов операндов, поэтому 1 // 2 равно 0, а 1.0 // 2.0 также равно 0,0.

    // всегда доступно в Python 2.2; его не нужно включать с помощью оператора __future__.

  • При включении from __future__ import division в модуль оператор / будет изменён так, чтобы возвращать результат истинного деления, поэтому 1/2 равно 0.5. Без оператора __future__ / по-прежнему означает классическое деление. Значение по умолчанию / не изменится до Python 3.0.

  • Классы могут определять методы с именами __truediv__() и __floordiv__() для перегрузки двух операторов деления. На уровне C в структуре PyNumberMethods также есть слоты, чтобы типы-расширения могли определить эти два оператора.

  • Python 2.2 поддерживает некоторые аргументы командной строки для проверки, будет ли код работать с изменённой семантикой деления. Запуск python с -Q warn приведёт к выдаче предупреждения всякий раз, когда деление применяется к двум целым числам. Это можно использовать для поиска кода, на который повлияло изменение, и его исправления. По умолчанию Python 2.2 будет просто выполнять классическое деление без предупреждения; в Python 2.3 предупреждение будет включено по умолчанию.

См. также

PEP 238 – Изменение оператора деления
Написан Моше Задкой и Гвидо ван Россумом. Реализован Гвидо ван Россумом.

Изменения в поддержке UnicodeUnicode Changes

Поддержка Unicode в Python была немного улучшена в версии 2.2. Строки Unicode обычно хранятся как UCS-2, в виде 16-битных целых чисел без знака. Python 2.2 также может быть скомпилирован для использования UCS-4, 32-битных целых чисел без знака, в качестве внутренней кодировки путём передачи --enable-unicode=ucs4 сценарию configure. (Также можно указать --disable-unicode для полного отключения поддержки Unicode.)

При сборке для использования UCS-4 («широкий Python») интерпретатор может изначально обрабатывать символы Unicode от U+000000 до U+110000, поэтому диапазон допустимых значений для функции unichr() расширяется соответствующим образом. При использовании интерпретатора, скомпилированного для UCS-2 («узкий Python»), при значениях больше 65535 unichr() по-прежнему будет возбуждать исключение ValueError. Это всё описано в PEP 261, «Поддержка „широких“ символов Unicode»; обратитесь к нему за дальнейшими подробностями.

Ещё одно изменение объяснить проще. С момента своего появления строки Unicode поддерживают метод encode() для преобразования строки в выбранную кодировку, например UTF-8 или Latin-1. Симметричный метод decode([*encoding*])() был добавлен для 8-битных строк (но не для строк Unicode) в версии 2.2. decode() предполагает, что строка находится в указанной кодировке, и декодирует её, возвращая то, что возвращает кодек.

Используя эту новую возможность, были добавлены кодеки для задач, не связанных напрямую с Unicode. Например, добавлены кодеки для uu-кодирования, кодирования base64 из MIME и сжатия с помощью модуля zlib:

>>> s = """Here is a lengthy piece of redundant, overly verbose,
... and repetitive text.
... """
>>> data = s.encode('zlib')
>>> data
'x\x9c\r\xc9\xc1\r\x80 \x10\x04\xc0?Ul...'
>>> data.decode('zlib')
'Here is a lengthy piece of redundant, overly verbose,\nand repetitive text.\n'
>>> print s.encode('uu')
begin 666 <data>
M2&5R92!I<R!A(&QE;F=T:'D@<&EE8V4@;V8@<F5D=6YD86YT+"!O=F5R;'D@
>=F5R8F]S92P*86YD(')E<&5T:71I=F4@=&5X="X*

end
>>> "sheesh".encode('rot-13')
'furrfu'

Чтобы преобразовать экземпляр класса в Unicode, класс может определить метод __unicode__(), аналогично __str__().

encode(), decode() и __unicode__() были реализованы Marc-André Lemburg. Изменения для поддержки внутреннего использования UCS-4 были реализованы Fredrik Lundh и Martin von Löwis.

См. также

PEP 261 – Поддержка «широких» символов Unicode
Автор: Paul Prescod.

PEP 227: Вложенные области видимостиPEP 227: Nested Scopes

В Python 2.1 статически вложенные области видимости были добавлены как опциональная возможность, включаемая директивой from __future__ import nested_scopes. В версии 2.2 вложенные области видимости больше не нужно специально включать, они теперь присутствуют всегда. Остальная часть этого раздела – копия описания вложенных областей видимости из моего документа «What’s New in Python 2.1»; если вы читали его, когда вышла версия 2.1, можете пропустить остальную часть раздела.

Самое большое изменение, введённое в Python 2.1 и завершённое в 2.2, касается правил областей видимости Python. В Python 2.0 в любой момент времени для поиска имён переменных использовалось не более трёх пространств имён: локальное, модульное и встроенное. Это часто удивляло людей, потому что не соответствовало их интуитивным ожиданиям. Например, вложенное рекурсивное определение функции не работает:

def f():
    ...
    def g(value):
        ...
        return g(value-1) + 1
    ...

Функция g() всегда будет вызывать исключение NameError, потому что привязка имени g не находится ни в её локальном пространстве имён, ни в пространстве имён уровня модуля. На практике это не такая уж большая проблема (как часто вы рекурсивно определяете вложенные функции таким образом?), но это также делало использование выражения lambda более громоздким, и на практике это было проблемой. В коде, использующем lambda, часто можно встретить копирование локальных переменных путём передачи их в качестве значений аргументов по умолчанию.

def find(self, name):
    "Return list of any entries equal to 'name'"
    L = filter(lambda x, name=name: x == name,
               self.list_attribute)
    return L

В результате удобочитаемость кода Python, написанного в сильно функциональном стиле, сильно страдает.

Самое значительное изменение в Python 2.2 – добавление статической области видимости для решения этой проблемы. Первый эффект: аргумент по умолчанию name=name теперь необязателен в приведённом выше примере. Проще говоря, если имя переменной не получает значение внутри функции (присваиванием, или операторами def, class или import), то ссылки на переменную будут искаться в локальном пространстве имён окружающей области видимости. Более подробное объяснение правил и разбор реализации можно найти в PEP.

Это изменение может вызвать некоторые проблемы совместимости для кода, где одно и то же имя переменной используется как на уровне модуля, так и в качестве локальной переменной внутри функции, содержащей другие определения функций. Однако это кажется маловероятным, поскольку такой код и без того был бы довольно запутанным для чтения.

Один из побочных эффектов изменения: операторы from module import * и exec стали недопустимыми внутри области видимости функции при определённых условиях. Справочное руководство по Python всегда утверждало, что from module import * допустимо только на верхнем уровне модуля, но интерпретатор CPython ранее этого не проверял. В рамках реализации вложенных областей видимости компилятору, преобразующему исходный код Python в байт-код, необходимо генерировать разный код для доступа к переменным в объемлющей области. from module import * и exec не позволяют компилятору это определить, поскольку они добавляют в локальное пространство имён имена, неизвестные на этапе компиляции. Поэтому, если функция содержит определения функций или выражения lambda со свободными переменными, компилятор пометит это, возбуждая исключение SyntaxError.

Чтобы сделать предыдущее объяснение немного понятнее, вот пример:

x = 1
def f():
    # Следующая строка – синтаксическая ошибка
    exec 'x=2'
    def g():
        return x

Строка 4, содержащая оператор exec, является синтаксической ошибкой, так как exec определил бы новую локальную переменную с именем x, значение которой должно быть доступно из g().

Это не должно быть большой проблемой, поскольку exec редко используется в большинстве программ на Python (а когда используется, это часто признак плохого дизайна).

См. также

PEP 227 – Статически вложенные области видимости
Написан и реализован Джереми Хилтоном.

Новые и улучшенные модулиNew and Improved Modules

  • Модуль xmlrpclib был добавлен в стандартную библиотеку Fredrik Lundh и предоставляет поддержку для написания XML-RPC клиентов. XML-RPC – это простой протокол удалённого вызова процедур, построенный поверх HTTP и XML. Например, следующий фрагмент получает список RSS-каналов из O’Reilly Network, а затем выводит последние заголовки для одного канала:

    import xmlrpclib
    s = xmlrpclib.Server(
          'http://www.oreillynet.com/meerkat/xml-rpc/server.php')
    channels = s.meerkat.getChannels()
    # channels – это список словарей, например:
    # [{'id': 4, 'title': 'Freshmeat Daily News'}
    #  {'id': 190, 'title': '32Bits Online'},
    #  {'id': 4549, 'title': '3DGamers'}, ... ]
    
    # Получить элементы для одного канала
    items = s.meerkat.getItems( {'channel': 4} )
    
    # 'items' – это ещё один список словарей, например:
    # [{'link': 'http://freshmeat.net/releases/52719/',
    #   'description': 'Утилита, которая преобразует HTML в XSL FO.',
    #   {'title': 'html2fo 0.3 (По умолчанию)'}
    

    Модуль SimpleXMLRPCServer упрощает создание простых XML-RPC серверов. Смотрите http://www.xmlrpc.com/ для получения дополнительной информации об XML-RPC.

  • Новый модуль hmac реализует алгоритм HMAC, описанный в RFC 2104. (Предоставлено Gerhard Häring.)

  • Некоторые функции, которые раньше возвращали длинные кортежи, теперь возвращают псевдопоследовательности, которые по-прежнему ведут себя как кортежи, но также имеют мнемонические атрибуты, такие как memberst_mtime или tm_year. К усовершенствованным функциям относятся stat(), fstat(), statvfs() и fstatvfs() из модуля os, а также localtime(), gmtime() и strptime() из модуля time.

    Например, чтобы получить размер файла с помощью старых кортежей, пришлось бы писать что-то вроде file_size = os.stat(filename)[stat.ST_SIZE], но теперь это можно написать более понятно: file_size = os.stat(filename).st_size.

    Оригинальный патч для этой функции был предоставлен Ником Мэтьюсоном.

  • Профилировщик Python был значительно переработан, и исправлены различные ошибки в его выводе. (Авторы: Фред Л. Дрейк-мл. и Тим Питерс.)

  • Модуль socket может быть скомпилирован с поддержкой IPv6; укажите опцию --enable-ipv6 сценарию configure Python. (Предоставлено Jun-ichiro “itojun” Hagino.)

  • В модуль struct были добавлены два новых символа форматирования для 64-битных целых чисел на платформах, поддерживающих тип C long long. q – для знакового 64-битного целого, а Q – для беззнакового. Значение возвращается как целое типа long в Python. (Предоставлено Tim Peters.)

  • В интерактивном режиме интерпретатора появилась новая встроенная функция help(), использующая модуль pydoc, представленный в Python 2.1, для предоставления интерактивной справки. help(object) отображает любой доступный текст справки о object. help() без аргументов открывает утилиту онлайн-справки, где можно вводить имена функций, классов или модулей для чтения их справки. (Предоставлено Guido van Rossum, с использованием модуля pydoc от Ka-Ping Yee.)

  • В движок SRE, лежащий в основе модуля re, были внесены различные исправления ошибок и улучшения производительности. Например, функции re.sub() и re.split() были переписаны на C. Ещё один предоставленный патч ускоряет определённые диапазоны символов Unicode в два раза, а новый метод finditer() возвращает итератор по всем непересекающимся совпадениям в заданной строке. (SRE поддерживается Fredrik Lundh. Патч BIGCHARSET был предоставлен Martin von Löwis.)

  • Модуль smtplib теперь поддерживает RFC 2487, «Secure SMTP over TLS», так что теперь можно шифровать SMTP-трафик между программой Python и агентом передачи почты, которому передаётся сообщение. smtplib также поддерживает SMTP-аутентификацию. (Предоставлено Gerhard Häring.)

  • Модуль imaplib, поддерживаемый Piers Lauder, получил поддержку нескольких новых расширений: расширения NAMESPACE, определённого в RFC 2342, SORT, GETACL и SETACL. (Предоставлено Anthony Baxter и Michel Pelletier.)

  • Разбор адресов электронной почты в модуле rfc822 теперь соответствует RFC 2822, обновлению RFC 822. (Имя модуля не будет изменено на rfc2822.) Также был добавлен новый пакет email для анализа и генерации сообщений электронной почты. (Предоставлено Barry Warsaw, возник из его работы над Mailman.)

  • Модуль difflib теперь содержит новый класс Differ для создания удобочитаемых списков изменений («дельты») между двумя последовательностями строк текста. Также имеются две функции-генератора, ndiff() и restore(), которые соответственно возвращают дельту из двух последовательностей или одну из исходных последовательностей из дельты. (Черновая работа предоставлена David Goodger, из кода ndiff.py Тима Петерса, который затем сделал генераторизацию.)

  • Новые константы ascii_letters, ascii_lowercase и ascii_uppercase были добавлены в модуль string. В стандартной библиотеке было несколько модулей, которые использовали string.letters для обозначения диапазонов A-Za-z, но это предположение неверно при использовании локалей, потому что string.letters меняется в зависимости от набора допустимых символов, определённого текущей локалью. Все проблемные модули были исправлены на использование ascii_letters вместо этого. (Сообщено неизвестным лицом; исправлено Fred L. Drake, Jr.)

  • Модуль mimetypes теперь упрощает использование альтернативных баз MIME-типов за счёт добавления класса MimeTypes, который принимает список имён файлов для разбора. (Предоставлено Fred L. Drake, Jr.)

  • Класс Timer был добавлен в модуль threading, который позволяет планировать выполнение действия в определённый момент в будущем. (Предоставлено Itamar Shtull-Trauring.)

Изменения и исправления в интерпретатореInterpreter Changes and Fixes

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

  • Функции профилирования и трассировки теперь могут быть реализованы на C, что работает намного быстрее, чем функции на Python, и должно снизить накладные расходы на профилирование и трассировку. Это будет интересно авторам сред разработки для Python. В API Python добавлены две новые функции на C: PyEval_SetProfile и PyEval_SetTrace. Существующие функции sys.setprofile() и sys.settrace() по-прежнему существуют, просто теперь они используют новый интерфейс на C. (Автор: Фред Л. Дрейк мл.)

  • Был добавлен ещё один низкоуровневый API, представляющий интерес в первую очередь для разработчиков отладчиков Python и инструментов разработки. PyInterpreterState_Head и PyInterpreterState_Next позволяют вызывающему коду перебрать все существующие объекты интерпретаторов; PyInterpreterState_ThreadHead и PyThreadState_Next позволяют перебрать все состояния потоков для данного интерпретатора. (Автор: Дэвид Бизли.)

  • Интерфейс сборщика мусора на уровне C был изменён, чтобы упростить написание типов расширений, поддерживающих сборку мусора, и отладку неправильного использования функций. Различные функции получили немного другую семантику, поэтому ряд функций пришлось переименовать. Расширения, использующие старый API, по-прежнему будут компилироваться, но не будут участвовать в сборке мусора, поэтому их обновление для версии 2.2 следует считать довольно приоритетным.

    Чтобы обновить модуль расширения до нового API, выполните следующие шаги:

  • Переименовать Py_TPFLAGS_GC в PyTPFLAGS_HAVE_GC.

  • Использовать PyObject_GC_New или PyObject_GC_NewVar для выделения

    объектов и PyObject_GC_Del для их освобождения.

  • Переименовать PyObject_GC_Init в PyObject_GC_Track и

    PyObject_GC_Fini в PyObject_GC_UnTrack.

  • Убрать PyGC_HEAD_SIZE из расчётов размера объекта.

  • Убрать вызовы PyObject_AS_GC и PyObject_FROM_GC.

  • Новая форматная последовательность et была добавлена в PyArg_ParseTuple; et принимает как параметр, так и имя кодировки, и преобразует параметр в заданную кодировку, если параметр оказывается строкой Unicode, или оставляет его без изменений, если это 8-битная строка, предполагая, что она уже находится в нужной кодировке. Это отличается от форматного символа es, который предполагает, что 8-битные строки находятся в кодировке ASCII по умолчанию, и преобразует их в указанную новую кодировку. (Автор: М.-А. Лембург, используется для поддержки MBCS в Windows, описанной в следующем разделе.)

  • Была добавлена другая функция разбора аргументов, PyArg_UnpackTuple, которая проще и, предположительно, быстрее. Вместо указания форматной строки вызывающий код просто задаёт минимальное и максимальное количество ожидаемых аргументов и набор указателей на переменные типа PyObject*, которые будут заполнены значениями аргументов.

  • Два новых флага METH_NOARGS и METH_O доступны в таблицах определений методов для упрощения реализации методов без аргументов или с одним нетипизированным аргументом. Вызов таких методов более эффективен, чем вызов соответствующего метода, использующего METH_VARARGS. Кроме того, старый стиль написания C-методов METH_OLDARGS теперь официально устарел.

  • Две новые функции-обёртки, PyOS_snprintf и PyOS_vsnprintf, были добавлены для предоставления кроссплатформенных реализаций относительно новых API библиотеки C: snprintf и vsnprintf. В отличие от стандартных функций sprintf и vsprintf, версии Python проверяют границы используемого буфера для защиты от переполнения буфера. (Автор: М.-А. Лембург.)

  • Функция _PyTuple_Resize лишилась неиспользуемого параметра, так что теперь она принимает 2 параметра вместо 3. Третий аргумент никогда не использовался, и его можно просто отбросить при переносе кода с более ранних версий на Python 2.2.

Другие изменения и исправленияOther Changes and Fixes

Как обычно, было множество других улучшений и исправлений ошибок, разбросанных по всему дереву исходного кода. Поиск по журналам изменений CVS показывает, что между Python 2.1 и 2.2 было применено 527 патчей и исправлено 683 ошибки; в 2.2.1 применено 139 патчей и исправлено 143 ошибки; в 2.2.2 применено 106 патчей и исправлено 82 ошибки. Эти цифры, вероятно, занижены.

Некоторые из наиболее заметных изменений:

  • Код порта Python для MacOS, поддерживаемый Джеком Янсеном, теперь хранится в главном дереве CVS Python, и было внесено много изменений для поддержки MacOS X.

    Наиболее значительным изменением является возможность сборки Python в виде фреймворка, достигаемая передачей опции --enable-framework скрипту configure при компиляции Python. По словам Джека Янсена, «Это устанавливает самодостаточную установку Python вместе с OS X framework "glue" в /Library/Frameworks/Python.framework (или другое место по выбору). Пока что от этого мало непосредственной выгоды (на самом деле есть недостаток: нужно изменить PATH, чтобы можно было найти Python), но это основа для создания полноценного приложения Python, портирования MacPython IDE, возможного использования Python в качестве стандартного языка сценариев OSA и многого другого».

    Большинство модулей инструментария MacPython, которые взаимодействуют с API MacOS, такими как оконный интерфейс, QuickTime, скрипты и т.д., были портированы на OS X, но они были оставлены закомментированными в setup.py. Желающие поэкспериментировать с этими модулями могут раскомментировать их вручную.

  • Именованные аргументы, переданные встроенным функциям, которые их не принимают, теперь вызывают исключение TypeError с сообщением «function не принимает именованных аргументов».

  • Слабые ссылки, добавленные в Python 2.1 как модуль расширения, теперь являются частью ядра, поскольку они используются в реализации классов нового стиля. Поэтому исключение ReferenceError переместилось из модуля weakref и стало встроенным исключением.

  • Новый скрипт, Tools/scripts/cleanfuture.py от Тима Питерса, автоматически удаляет устаревшие инструкции __future__ из исходного кода Python.

  • Дополнительный аргумент flags был добавлен во встроенную функцию compile(), так что поведение инструкций __future__ теперь может правильно наблюдаться в симулированных оболочках, таких как представленные IDLE и другими средами разработки. Это описано в PEP 264. (Предложено Майклом Хадсоном.)

  • Новая лицензия, введённая в Python 1.6, не была совместима с GPL. Это исправлено небольшими текстовыми изменениями в лицензии 2.2, так что теперь снова разрешено встраивать Python в программы под GPL. Обратите внимание, что сам Python не под GPL, а распространяется по лицензии, по существу эквивалентной лицензии BSD, как и раньше. Изменения лицензии также были применены к релизам Python 2.0.1 и 2.1.1.

  • При получении имени файла в Юникоде на Windows Python теперь преобразует его в строку в кодировке MBCS, используемую файловыми API Microsoft. Поскольку MBCS явно используется файловыми API, выбор Python в качестве кодировки по умолчанию ASCII оказывается неудобным. На Unix используется набор символов локали, если доступна locale.nl_langinfo(CODESET)(). (Поддержка Windows была добавлена Марком Хаммондом при содействии Марка-Андре Лембурга. Поддержка Unix была добавлена Мартином фон Лёвисом.)

  • Поддержка больших файлов теперь включена на Windows. (Автор: Tim Peters.)

  • Скрипт Tools/scripts/ftpmirror.py теперь разбирает файл .netrc, если таковой имеется. (Предложено Майком Ромбергом.)

  • Некоторые возможности объекта, возвращаемого функцией xrange(), теперь помечены как устаревшие и вызывают предупреждения при обращении к ним; они исчезнут в Python 2.3. Объекты xrange пытались притворяться полноценными типами последовательностей, поддерживая срезы, умножение последовательностей и оператор in, но эти возможности редко использовались и поэтому были подвержены ошибкам. Метод tolist() и атрибуты start, stop, step также помечены как устаревшие. На уровне C четвёртый аргумент функции PyRange_New, repeat, также устарел.

  • Было множество патчей к реализации словарей, в основном для исправления потенциальных дампов ядра, если словарь содержит объекты, которые хитро изменили своё хеш-значение или изменили сам словарь, в котором содержались. Некоторое время python-dev вошёл в плавный ритм: Майкл Хадсон находил случай, приводящий к дампу ядра, Тим Питерс исправлял ошибку, Майкл находил другой случай, и так по кругу.

  • В Windows Python теперь можно компилировать с помощью Borland C благодаря ряду патчей, предоставленных Стивеном Хансеном, хотя результат пока не полностью функционален. (Но это is прогресс...)

  • Ещё одно улучшение Windows: компания Wise Solutions щедро предоставила PythonLabs возможность использовать их систему InstallerMaster 8.1. Ранние инсталляторы PythonLabs для Windows использовали Wise 5.0a, который уже начинал показывать свой возраст. (Упаковано Тимом Питерсом.)

  • Файлы, заканчивающиеся на .pyw, теперь можно импортировать в Windows. .pyw – это особенность только Windows, используемая для указания, что скрипт должен запускаться с помощью PYTHONW.EXE вместо PYTHON.EXE, чтобы предотвратить появление консоли DOS для вывода результатов. Этот патч делает возможным импорт таких скриптов, если их также можно использовать как модули. (Реализовано Дэвидом Боленом.)

  • На платформах, где Python использует функцию C dlopen для загрузки модулей расширения, теперь можно задавать флаги, используемые dlopen, с помощью функций sys.getdlopenflags() и sys.setdlopenflags(). (Автор: Брам Сток.)

  • Встроенная функция pow() больше не поддерживает 3 аргумента при передаче чисел с плавающей запятой. pow(x, y, z) возвращает (x**y) % z, но это никогда не полезно для чисел с плавающей запятой, и конечный результат непредсказуемо варьируется в зависимости от платформы. Вызов вида pow(2.0, 8.0, 7.0) теперь вызовет исключение TypeError.

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

Автор хотел бы поблагодарить следующих людей за предложения, исправления и помощь с различными черновиками этой статьи: Фред Бреммер, Кейт Бриггс, Эндрю Далк, Фред Л. Дрейк-младший, Карел Феллингер, Дэвид Гуджер, Марк Хаммонд, Стивен Хансен, Майкл Хадсон, Джек Янсен, Марк-Андре Лембург, Мартин фон Лёвис, Фредрик Лунд, Майкл МакЛей, Ник Мэтьюсон, Пол Мур, Густаво Нимейер, Дон О’Доннелл, Юнас Пааласма, Тим Питерс, Йенс Кваде, Том Рейнхардт, Нил Шеменауэр, Гвидо ван Россум, Грег Уорд, Эдвард Уэлборн.