Содержание страницы
Что нового в Python 2.2¶What’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 для этой новой возможности.
PEP 252 и 253: Изменения типов и классов¶PEPs 252 and 253: Type and Class Changes
Самые большие и далеко идущие изменения в Python 2.2 касаются модели объектов и классов. Изменения должны быть обратно совместимы, поэтому ваш код, скорее всего, продолжит работать без изменений, но эти изменения дают потрясающие новые возможности. Перед тем как приступить к самому длинному и сложному разделу этой статьи, я дам обзор изменений и выскажу несколько замечаний.
Давным-давно я написал веб-страницу с перечнем недостатков дизайна 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)– это метод, который извлекает значение атрибута из объекта.__set__(object, value)устанавливает атрибут объекта в значение.__delete__(object, value)удаляет атрибут значение объекта объекта.
Например, при записи 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()
не будет найден вообще. Это плохо, потому что если метод save()
C сохраняет некоторое внутреннее состояние, специфичное для C, то
его невызов приведёт к тому, что это состояние никогда не будет сохранено.
Классы нового стиля следуют другому алгоритму, который немного сложнее объяснить, но делает правильное дело в этой ситуации. (Обратите внимание, что Python 2.3 изменяет этот алгоритм на тот, который в большинстве случаев даёт те же результаты, но даёт более полезные результаты для действительно сложных графов наследования.)
Перечислить все базовые классы, следуя классическому правилу поиска, и включать класс несколько раз, если он посещается повторно. В приведённом примере список посещённых классов: [
D,B,A,C,A].Проверить список на наличие дублирующихся классов. Если таковые найдены, удалить все вхождения, кроме одного, оставив последнее в списке. В приведённом примере список становится [
D,B,C,A] после удаления дубликатов.
Следуя этому правилу, обращение к D.save() вернёт C.save(),
что и является нужным поведением. Это правило поиска совпадает с правилом,
используемым в Common Lisp. Новая встроенная функция super() предоставляет способ
получить суперклассы класса без необходимости повторной реализации алгоритма
Python. Наиболее часто используемой формой будет super(class, obj), которая
возвращает связанный объект суперкласса (не сам объект класса). Эта форма
будет использоваться в методах для вызова метода суперкласса; например,
метод save() D будет выглядеть следующим образом:
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 не найден
в словаре экземпляра.
Однако поддержка свойств (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 ...
# Определить свойство. Метод '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
>>>
В Python 2.2 оператор for больше не требует последовательности; он ожидает объект, для которого 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.
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×N так, чтобы ни один ферзь не угрожал другому) и задачи об обходе коня (маршрут, по которому конь посещает каждую клетку доски N×N, не посещая ни одну клетку дважды).
Идея генераторов пришла из других языков программирования, особенно Icon (https://www.cs.arizona.edu/icon/), где идея генераторов является центральной. В Icon каждое выражение и вызов функции ведут себя как генератор. Один пример из «An Overview of the Icon Programming Language» по адресу 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 - 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 – Изменение оператора деления
Написан Моше Задкой и Гвидо ван Россумом. Реализован Гвидо ван Россумом.
Изменения в поддержке Unicode¶Unicode 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. В Python 2.2 для 8-битных строк (но не для строк Unicode) был добавлен симметричный метод decode([*encoding*]). 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__() были реализованы Марком-Андре Лембургом. Изменения для поддержки UCS-4 внутри были реализованы Фредриком Лундом и Мартином фон Лёвисом.
См. также
- PEP 261 – Поддержка «широких» символов Unicode
Автор: Paul Prescod.
PEP 227: Вложенные области видимости¶PEP 227: Nested Scopes
В Python 2.1 статически вложенные области видимости были добавлены как опциональная возможность, которую нужно было включать директивой from __future__ import nested_scopes. В Python 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():
# Следующая строка – синтаксическая ошибка
exec 'x=2'
def g():
return x
Строка 4, содержащая оператор exec, является синтаксической ошибкой, поскольку
exec определил бы новую локальную переменную с именем x, значение которой должно
быть доступно через g().
Это не должно быть большим ограничением, поскольку exec редко используется в большинстве кода Python (а когда используется, это часто признак плохого дизайна).
См. также
- PEP 227 – Статически вложенные области видимости
Написан и реализован Джереми Хилтоном.
Новые и улучшенные модули¶New and Improved Modules
Модуль
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 – это список словарей, например: # [{'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 серверов. Подробнее об XML-RPC см. http://xmlrpc.scripting.com/.Новый модуль
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-битных целых чисел на платформах, поддерживающих тип Clong long.qпредназначен для знакового 64-битного целого числа, аQ– для беззнакового. Значение возвращается в длинном целочисленном типе Python. (Автор: Tim Peters.)В интерактивном режиме интерпретатора появилась новая встроенная функция
help(), которая использует модульpydoc, представленный в Python 2.1, для организации интерактивной справки.help(object)выводит любую доступную справку об объекте.help()без аргументов запускает утилиту онлайн-справки, где можно вводить имена функций, классов или модулей для чтения их справки. (Автор: Гвидо ван Россум, с использованием модуля Ka-Ping Yeepydoc.)В движок SRE, лежащий в основе модуля
re, внесены различные исправления ошибок и улучшения производительности. Например, функцииre.sub()иre.split()были переписаны на C. Ещё один патч ускоряет некоторые диапазоны символов Unicode в два раза, а также появился новыйfinditer()метод, возвращающий итератор по всем непересекающимся совпадениям в заданной строке. (SRE поддерживается Фредриком Лундом. Патч BIGCHARSET предоставлен Мартином фон Лёвисом.)Модуль
smtplibтеперь поддерживает RFC 2487, «Безопасный SMTP через TLS», так что теперь можно шифровать трафик SMTP между программой на Python и агентом передачи почты, которому передаётся сообщение.smtplibтакже поддерживает аутентификацию SMTP. (Автор: Gerhard Häring.)Модуль
imaplib, поддерживаемый Пирсом Лодером, получил поддержку нескольких новых расширений: расширение NAMESPACE, определённое в RFC 2342, SORT, GETACL и SETACL. (Авторы: Энтони Бакстер и Мишель Пеллетье.)Разбор адресов электронной почты в модуле
rfc822теперь соответствует RFC 2822, обновлению RFC 822. (Имя модуля не будет изменено наrfc2822.) Также добавлен новый пакет,email, для разбора и создания сообщений электронной почты. (Автор: Барри Варшава, работа выросла из его работы над Mailman.)Модуль
difflibтеперь содержит новый классDifferдля создания читаемых списков изменений («дельты») между двумя последовательностями строк текста. Также появились две функции-генератора,ndiff()иrestore(), которые возвращают дельту из двух последовательностей или одну из исходных последовательностей из дельты. (Черновая работа выполнена Дэвидом Гуджером, на основе кода ndiff.py Тима Питерса, который затем выполнил генераторизацию.)Новые константы
ascii_letters,ascii_lowercaseиascii_uppercaseбыли добавлены в модульstring. Некоторые модули в стандартной библиотеке использовалиstring.lettersдля обозначения диапазонов A-Za-z, но это предположение неверно при использовании локалей, потому чтоstring.lettersизменяется в зависимости от набора допустимых символов, определённых текущей локалью. Все ошибочные модули были исправлены для использованияascii_lettersвместо этого. (Сообщено неизвестным лицом; исправлено Фредом Л. Дрейком-мл.)Модуль
mimetypesтеперь упрощает использование альтернативных баз данных MIME-типов за счёт добавления классаMimeTypes, который принимает список имён файлов для разбора. (Автор: Фред Л. Дрейк-мл.)Класс
Timerбыл добавлен в модульthreading, который позволяет планировать выполнение действия в будущем. (Автор: Итамар Штуль-Трауринг.)
Изменения и исправления в интерпретаторе¶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 по умолчанию в Python, и преобразует их в указанную новую кодировку. (Автор: М.-А. Лембург; используется для поддержки MBCS в Windows, описанной в следующем разделе.)Добавлена другая функция разбора аргументов,
PyArg_UnpackTuple(), которая проще и, предположительно, быстрее. Вместо указания строки формата вызывающий просто задаёт минимальное и максимальное ожидаемое количество аргументов, а также набор указателей на переменныеPyObject*, которые будут заполнены значениями аргументов.В таблицах определений методов доступны два новых флага
METH_NOARGSиMETH_O, упрощающие реализацию методов без аргументов или с одним нетипизированным аргументом. Вызов таких методов эффективнее, чем вызов соответствующего метода, использующегоMETH_VARARGS. Кроме того, старый стиль написания методов на CMETH_OLDARGSтеперь официально устарел.Добавлены две новые функции-обёртки
PyOS_snprintf()иPyOS_vsnprintf(), предоставляющие кроссплатформенные реализации для относительно новых API библиотеки Csnprintf()иvsnprintf(). В отличие от стандартных функцийsprintf()иvsprintf(), версии Python проверяют границы используемого буфера для защиты от переполнения буфера. (Автор: M.-A. Lemburg.)Функция
_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 в/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.Во встроенную функцию
compile()добавлен дополнительный аргумент flags, так что теперь поведение операторов__future__можно корректно наблюдать в симулированных оболочках, например в IDLE и других средах разработки. Это описано в PEP 264. (Автор: Michael Hudson.)Новая лицензия, введённая в Python 1.6, не была совместима с GPL. Это исправлено небольшими текстовыми изменениями в лицензии 2.2, так что теперь снова разрешено встраивать Python в программы под GPL. Обратите внимание, что сам Python не под GPL, а распространяется по лицензии, по существу эквивалентной лицензии BSD, как и раньше. Изменения лицензии также были применены к релизам Python 2.0.1 и 2.1.1.
При получении имени файла в Unicode на Windows Python теперь преобразует его в строку в кодировке MBCS, как используется API файлов Microsoft. Поскольку API файлов явно используют MBCS, выбор Python в пользу ASCII в качестве кодировки по умолчанию оказывается неудобным. На Unix используется набор символов локали, если доступен
locale.nl_langinfo(CODESET). (Поддержка Windows предоставлена Марком Хаммондом при содействии Марка-Андре Лембурга. Поддержка Unix добавлена Мартином фон Лёвисом.)Поддержка больших файлов теперь включена на Windows. (Автор: Tim Peters.)
Скрипт
Tools/scripts/ftpmirror.pyтеперь анализирует файл.netrc, если он есть. (Автор: Mike Romberg.)Некоторые возможности объекта, возвращаемого функцией
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(). (Автор: Bram Stolk.)Встроенная функция
pow()больше не поддерживает 3 аргумента, когда передаются числа с плавающей запятой.pow(x, y, z)возвращает(x**y) % z, но это никогда не бывает полезным для чисел с плавающей запятой, и конечный результат непредсказуемо варьируется в зависимости от платформы. Вызов видаpow(2.0, 8.0, 7.0)теперь вызовет исключениеTypeError.
Благодарности¶Acknowledgements
Автор хотел бы поблагодарить следующих людей за предложения, исправления и помощь с различными черновиками этой статьи: Фред Бреммер, Кейт Бриггс, Эндрю Далк, Фред Л. Дрейк-младший, Карел Феллингер, Дэвид Гуджер, Марк Хаммонд, Стивен Хансен, Майкл Хадсон, Джек Янсен, Марк-Андре Лембург, Мартин фон Лёвис, Фредрик Лунд, Майкл МакЛей, Ник Мэтьюсон, Пол Мур, Густаво Нимейер, Дон О’Доннелл, Юнас Пааласма, Тим Питерс, Йенс Кваде, Том Рейнхардт, Нил Шеменауэр, Гвидо ван Россум, Грег Уорд, Эдвард Уэлборн.