Что нового в Python 2.2

Автор

А.М. Кучлинг

Введение

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

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

В этой статье не делается попытка дать полную характеристику новых возможностей, а вместо этого представлен удобный обзор. Для получения полной информации следует обратиться к документации по Python 2.2, например, Python Library Reference и Python Reference Manual. Если вы хотите понять полную реализацию и проектное обоснование изменения, обратитесь к PEP для конкретной новой функции.

ПЭПы 252 и 253: Изменения типа и класса

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

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

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

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

  • Теперь можно определять статические методы и методы класса, в дополнение к методам экземпляра, доступным в предыдущих версиях Python.

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

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

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

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

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

Старые и новые классы

Во-первых, вы должны знать, что в 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.

Дескрипторы

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

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

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

  • __name__ - это имя атрибута.

  • __doc__ - документальная строка атрибута.

  • __get__(object) - это метод, который извлекает значение атрибута из объекта.

  • __set__(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.

Более новые возможности, такие как слоты и свойства, также реализуются в виде новых видов дескрипторов, и нетрудно написать класс дескриптора, который делает что-то новое. Например, можно написать дескрипторный класс, позволяющий писать предварительные и последующие условия для метода в стиле Eiffel. Класс, использующий эту возможность, может быть определен следующим образом:

from eiffel import eiffelmethod

class C(object):
    def f(self, arg1, arg2):
        # The actual function
        ...
    def pre_f(self):
        # Check preconditions
        ...
    def post_f(self):
        # Check postconditions
        ...

    f = eiffelmethod(f, pre_f, post_f)

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

Множественное наследование: Алмазное правило

Множественное наследование также стало более полезным благодаря изменению правил, по которым разрешаются имена. Рассмотрим такой набор классов (диаграмма взята из 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 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):
        # Call superclass .save()
        super(D, self).save()
        # Save D's private information here
        ...

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

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

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

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

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

Однако поддержка properties в 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 ...

    # Define a property.  The 'delete this attribute'
    # method is defined as None, so the attribute
    # can't be deleted.
    size = property(get_size, set_size,
                    None,
                    "Storage size of this instance")

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

Наконец, можно ограничить список атрибутов, на которые можно ссылаться в объекте, используя атрибут класса new __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'

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

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

Еще одним существенным дополнением в версии 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:
    # do something for each line
    ...

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

См.также

PEP 234 - Итераторы

Написан Ка-Пингом Йи и GvR; реализован командой Python Labs, в основном GvR и Тимом Питерсом.

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

Генераторы - еще одна новая функция, которая взаимодействует с введением итераторов.

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

# A recursive generator that generates Tree leaves in 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-Queens (размещение $N$ ферзей на шахматной доске $NxN$ так, чтобы ни один ферзь не угрожал другому) и Knight’s Tour (маршрут, который ведет коня на каждую клетку шахматной доски $NxN$, не посещая ни одну клетку дважды).

Идея генераторов пришла из других языков программирования, особенно из Icon (https://www.cs.arizona.edu/icon/), где идея генераторов является центральной. В Icon каждое выражение и вызов функции ведет себя как генератор. Один пример из «Обзора языка программирования Icon» на сайте https://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 - Простые генераторы

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

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

В последних версиях различие между обычными целыми числами, которые на большинстве машин являются 32-битными значениями, и длинными целыми числами, которые могут иметь произвольный размер, стало раздражать. Например, на платформах, поддерживающих файлы размером более 2**32 байт, метод tell() для объектов файлов должен возвращать длинное целое число. Однако в Python были различные части, которые ожидали простые целые числа и выдавали ошибку, если вместо них было предоставлено длинное целое число. Например, в Python 1.5 в качестве индекса фрагмента можно было использовать только обычные целые числа, и 'abc'[1L:] вызывал исключение TypeError с сообщением «индекс фрагмента должен быть 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: Изменение оператора деления

Самое спорное изменение в 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 и так далее. «Деление на пол» - это то, что в настоящее время делает оператор 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 - Изменение оператора деления

Авторы: Моше Задка и Гвидо ван Россум. Реализовано Гвидо ван Россумом.

Изменения в Юникоде

Поддержка Юникода в 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 поддерживали метод encode() для преобразования строки в выбранную кодировку, такую как UTF-8 или Latin-1. Симметричный метод decode([*encoding*]) был добавлен к 8-битным строкам (хотя и не к строкам Юникода) в версии 2.2. decode() предполагает, что строка находится в указанной кодировке, и декодирует ее, возвращая то, что возвращается кодеком.

Используя эту новую возможность, были добавлены кодеки для задач, не связанных напрямую с Unicode. Например, были добавлены кодеки для uu-encoding, кодировки MIME base64 и сжатия с помощью модуля 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__(), аналогичный __str__().

encode(), decode() и __unicode__() были реализованы Марком-Андре Лембургом. Изменения для поддержки внутреннего использования UCS-4 были выполнены Фредриком Лундхом и Мартином фон Лёвисом.

См.также

PEP 261 - Поддержка «широких» символов Unicode

Автор Пол Прескод.

PEP 227: Вложенные диапазоны

В Python 2.1 статически вложенные диапазоны были добавлены как необязательная возможность, которая включалась директивой from __future__ import nested_scopes. В версии 2.2 вложенные диапазоны больше не нужно специально включать, теперь они присутствуют всегда. Остальная часть этого раздела представляет собой копию описания вложенных диапазонов из моего документа «Что нового в 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():
    # The next line is a syntax error
    exec 'x=2'
    def g():
        return x

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

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

См.также

PEP 227 - Статически вложенные диапазоны

Написано и реализовано Джереми Хилтоном.

Новые и улучшенные модули

  • Модуль xmlrpclib был внесен в стандартную библиотеку Фредриком Лундом, обеспечивая поддержку написания клиентов 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 is a list of dictionaries, like this:
    # [{'id': 4, 'title': 'Freshmeat Daily News'}
    #  {'id': 190, 'title': '32Bits Online'},
    #  {'id': 4549, 'title': '3DGamers'}, ... ]
    
    # Get the items for one channel
    items = s.meerkat.getItems( {'channel': 4} )
    
    # 'items' is another list of dictionaries, like this:
    # [{'link': 'http://freshmeat.net/releases/52719/',
    #   'description': 'A utility which converts HTML to XSL FO.',
    #   'title': 'html2fo 0.3 (Default)'}, ... ]
    

    Модуль SimpleXMLRPCServer позволяет легко создавать простые серверы XML-RPC. Более подробную информацию о XML-RPC см. на сайте http://xmlrpc.scripting.com/.

  • Новый модуль hmac реализует алгоритм HMAC, описанный в RFC 2104. (Внесен Герхардом Херингом.)

  • Несколько функций, которые первоначально возвращали длинные кортежи, теперь возвращают псевдопоследовательности, которые по-прежнему ведут себя как кортежи, но также имеют мнемонические атрибуты, такие как 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. (Внесено Дзюн-итиро «itojun» Хагино.)

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

  • В интерактивном режиме интерпретатора есть новая встроенная функция help(), которая использует модуль pydoc, представленный в Python 2.1, для предоставления интерактивной справки. help(object) выводит любой доступный текст справки об объекте. help() без аргумента переводит вас в интерактивную справочную утилиту, где вы можете ввести имена функций, классов или модулей, чтобы прочитать их справочный текст. (Внесено Гвидо ван Россумом, с использованием модуля pydoc Ка-Пинг Йи).

  • Различные исправления и улучшения производительности были внесены в механизм SRE, лежащий в основе модуля re. Например, функции re.sub() и re.split() были переписаны на C. Еще один внесенный патч ускоряет некоторые диапазоны символов Unicode в два раза, а новый метод finditer() возвращает итератор по всем непересекающимся совпадениям в заданной строке. (SRE поддерживается Фредриком Лундом. Патч BIGCHARSET был внесен Мартином фон Лёвисом).

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

  • Модуль imaplib, поддерживаемый Пирсом Лаудером, имеет поддержку нескольких новых расширений: расширение NAMESPACE, определенное в RFC 2342, SORT, GETACL и SETACL. (Вклад Энтони Бакстера и Мишеля Пеллетье).

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

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

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

  • Модуль mimetypes теперь облегчает использование баз данных альтернативных MIME-типов благодаря добавлению класса MimeTypes, который принимает список имен файлов, подлежащих разбору. (Внесено Фредом Л. Дрейком, младшим).

  • В модуль Timer был добавлен класс threading, который позволяет запланировать выполнение действия на некоторое будущее время. (Внесено Итамаром Штулл-Траурингом.)

Изменения и исправления в интерпретаторе

Некоторые изменения затрагивают только тех, кто работает с интерпретатором 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().

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

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

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

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

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

Другие изменения и исправления

Как обычно, по всему дереву исходников разбросано множество других улучшений и исправлений. Поиск по журналам изменений 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 в /Library/Frameworks/Python.framework (или другое место по выбору). На данный момент от этого мало непосредственной пользы (на самом деле, есть недостаток в том, что вам придется изменить PATH, чтобы найти Python), но это основа для создания полноценного приложения Python, переноса MacPython IDE, возможного использования Python в качестве стандартного языка сценариев OSA и многого другого.»

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

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

  • Слабые ссылки, добавленные в 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.

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

  • Поддержка больших файлов теперь включена в Windows. (Внесено Тимом Питерсом.)

  • Сценарий 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 благодаря ряду исправлений, внесенных Стивеном Хансеном, хотя результат еще не полностью функционален. (Но это это прогресс…)

  • Еще одно усовершенствование 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.

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

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

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