Что нового в Python 2.4

Автор:

А.М. Кючлинг

В этой статье рассказывается о новых возможностях Python 2.4.1, выпущенного 30 марта 2005 года.

Python 2.4 - это релиз среднего размера. В нем не так много изменений, как в радикальном Python 2.2, но больше возможностей, чем в консервативном выпуске 2.3. Наиболее значительными новыми возможностями языка являются декораторы функций и генераторы выражений; большинство других изменений касаются стандартной библиотеки.

Согласно журналам изменений CVS, между Python 2.3 и 2.4 было применено 481 исправление и исправлено 502 ошибки. Обе цифры, скорее всего, занижены.

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

PEP 218: Встроенные объекты множеств

В Python 2.3 появился модуль sets. Реализации типов данных множеств на языке C теперь добавлены в ядро Python в виде двух новых встроенных типов, set(iterable) и frozenset(iterable). Они обеспечивают высокую скорость операций для проверки принадлежности, удаления дубликатов из последовательностей, а также для математических операций, таких как объединения, пересечения, разности и симметричные разности.

>>> a = set('abracadabra')              # form a set from a string
>>> 'z' in a                            # fast membership testing
False
>>> a                                   # unique letters in a
set(['a', 'r', 'b', 'c', 'd'])
>>> ''.join(a)                          # convert back into a string
'arbcd'

>>> b = set('alacazam')                 # form a second set
>>> a - b                               # letters in a but not in b
set(['r', 'd', 'b'])
>>> a | b                               # letters in either a or b
set(['a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'])
>>> a & b                               # letters in both a and b
set(['a', 'c'])
>>> a ^ b                               # letters in a or b but not both
set(['r', 'd', 'b', 'm', 'z', 'l'])

>>> a.add('z')                          # add a new element
>>> a.update('wxy')                     # add multiple new elements
>>> a
set(['a', 'c', 'b', 'd', 'r', 'w', 'y', 'x', 'z'])
>>> a.remove('x')                       # take one element out
>>> a
set(['a', 'c', 'b', 'd', 'r', 'w', 'y', 'z'])

Тип frozenset() - это неизменяемая версия set(). Поскольку он неизменяемый и хэшируемый, его можно использовать как ключ словаря или как член другого набора.

Модуль sets остается в стандартной библиотеке и может быть полезен, если вы хотите подклассифицировать классы Set или ImmutableSet. В настоящее время нет планов по выводу модуля из эксплуатации.

См.также

PEP 218 - Добавление встроенного типа объекта Set

Первоначально предложена Грегом Уилсоном и в конечном итоге реализована Раймондом Хеттингером.

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

Длительный процесс перехода на этот PEP, начатый в Python 2.2, делает еще один шаг вперед в Python 2.4. В 2.3 некоторые целочисленные операции, которые вели себя по-другому после объединения int/long, вызывали предупреждения FutureWarning и возвращали значения, ограниченные 32 или 64 битами (в зависимости от вашей платформы). В 2.4 эти выражения больше не выдают предупреждения и вместо них выдают другой результат, который обычно является длинным целым числом.

Проблемные выражения - это в основном сдвиги влево и длинные шестнадцатеричные и восьмеричные константы. Например, выражение 2 << 32 в версии 2.3 выдает предупреждение, поскольку на 32-битных платформах оно оценивается в 0. В Python 2.4 это выражение теперь возвращает правильный ответ - 8589934592.

См.также

PEP 237 - Объединение длинных целых и целых чисел

Оригинальный PEP написан Моше Задкой и GvR. Изменения для 2.4 были реализованы Калле Свенссоном.

PEP 289: Генератор выражений

Функция итератора, появившаяся в Python 2.2, и модуль itertools облегчают написание программ, которые циклически просматривают большие наборы данных, не имея в памяти всего набора данных за один раз. Списочные компиляции не очень хорошо вписываются в эту картину, потому что они создают объект-список Python, содержащий все элементы. Это неизбежно тянет все объекты в память, что может стать проблемой, если ваш набор данных очень велик. При попытке написать программу в функциональном стиле естественно было бы написать что-то вроде:

links = [link for link in get_all_links() if not link.followed]
for link in links:
    ...

вместо

for link in get_all_links():
    if link.followed:
        continue
    ...

Первая форма более лаконична и, возможно, более читабельна, но если вы имеете дело с большим количеством объектов ссылок, вам придется написать вторую форму, чтобы избежать одновременного наличия всех объектов ссылок в памяти.

Выражения-генераторы работают так же, как и списочные компиляции, но не материализуют весь список, а создают генератор, который будет возвращать элементы по одному. Приведенный выше пример можно записать так:

links = (link for link in get_all_links() if not link.followed)
for link in links:
    ...

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

print sum(obj.count for obj in list_all_objects())

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

См.также

PEP 289 - Генератор выражений

Предложена Раймондом Хеттингером, реализована Дживоном Со, а на ранних этапах работы возглавлялась Хе-Шиком Чангом.

PEP 292: Простые подстановки строк

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

Обычный способ подстановки переменных по имени - оператор %:

>>> '%(page)i: %(title)s' % {'page':2, 'title': 'The Best of Times'}
'2: The Best of Times'

При написании строки шаблона можно легко забыть i или s после закрывающей скобки. Это не является большой проблемой, если шаблон находится в модуле Python, поскольку вы запускаете код, получаете сообщение «Unsupported format character» ValueError и устраняете проблему. Однако рассмотрим такое приложение, как Mailman, где строки шаблонов или переводы редактируются пользователями, не знакомыми с языком Python. Синтаксис строки форматирования сложно объяснить таким пользователям, а если они допустят ошибку, им будет сложно предоставить полезную обратную связь.

PEP 292 добавляет класс Template в модуль string, который использует $ для обозначения подстановки:

>>> import string
>>> t = string.Template('$page: $title')
>>> t.substitute({'page':2, 'title': 'The Best of Times'})
'2: The Best of Times'

Если ключ отсутствует в словаре, метод substitute() вызовет ошибку KeyError. Существует также метод safe_substitute(), который игнорирует отсутствующие ключи:

>>> t = string.Template('$page: $title')
>>> t.safe_substitute({'page':3})
'3: $title'

См.также

PEP 292 - Более простые подстановки строк

Автор и исполнитель Барри Варшава.

PEP 318: Декораторы для функций и методов

Python 2.2 расширил объектную модель Python, добавив статические методы и методы классов, но не расширил синтаксис Python, чтобы обеспечить новый способ определения статических методов или методов классов. Вместо этого вам нужно было написать оператор def обычным способом и передать полученный метод в функцию staticmethod() или classmethod(), которая обернула бы функцию в метод нового типа. Ваш код выглядел бы следующим образом:

class C:
   def meth (cls):
       ...

   meth = classmethod(meth)   # Rebind name to wrapped-up class method

Если метод очень длинный, можно легко пропустить или забыть о вызове classmethod() после тела функции.

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

Новая возможность называется «декораторы функций». Название происходит от идеи, что classmethod(), staticmethod() и друзья хранят дополнительную информацию об объекте функции; они декорируют функции более подробной информацией.

Эта нотация заимствована из Java и использует символ '@' в качестве индикатора. Используя новый синтаксис, пример выше будет выглядеть так:

class C:

   @classmethod
   def meth (cls):
       ...

Символ @classmethod является сокращением для присваивания meth=classmethod(meth). В общем случае, если у вас есть следующее:

@A
@B
@C
def f ():
    ...

Это эквивалентно следующему коду предварительного декорирования:

def f(): ...
f = A(B(C(f)))

Декораторы должны располагаться в строке перед определением функции, по одному декоратору на строку, и не могут находиться в той же строке, что и оператор def, что означает, что @A def f(): ... является незаконным. Декорировать можно только определения функций, либо на уровне модуля, либо внутри класса; определения классов декорировать нельзя.

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

>>> def deco(func):
...    func.attr = 'decorated'
...    return func
...
>>> @deco
... def f(): pass
...
>>> f
<function f at 0x402ef0d4>
>>> f.attr
'decorated'
>>>

В качестве чуть более реалистичного примера можно привести следующий декоратор, проверяющий, что предоставленный аргумент является целым числом:

def require_int (func):
    def wrapper (arg):
        assert isinstance(arg, int)
        return func(arg)

    return wrapper

@require_int
def p1 (arg):
    print arg

@require_int
def p2(arg):
    print arg*2

Пример в PEP 318 содержит более сложную версию этой идеи, позволяющую как указать требуемый тип, так и проверить возвращаемый тип.

Функции-декораторы могут принимать аргументы. Если аргументы заданы, ваша функция-декоратор вызывается только с этими аргументами и должна вернуть новую функцию-декоратор; эта функция должна принимать единственную функцию и возвращать функцию, как было описано ранее. Другими словами, @A @B @C(args) становится:

def f(): ...
_deco = C(args)
f = A(B(_deco(f)))

Чтобы сделать это правильно, придется немного потрудиться, но это не слишком сложно.

Небольшое связанное с этим изменение делает атрибут func_name функций доступным для записи. Этот атрибут используется для отображения имен функций в трассировках, поэтому декораторы должны изменять имя любой новой функции, которая создается и возвращается.

См.также

PEP 318 - Декораторы для функций, методов и классов

Авторы: Кевин Д. Смит, Джим Джуэтт и Скип Монтанаро. Несколько человек написали патчи, реализующие декораторы функций, но тот, который действительно был проверен, был патчем #979728, написанным Марком Расселом.

https://wiki.python.org/moin/PythonDecoratorLibrary

Эта страница Wiki содержит несколько примеров декораторов.

PEP 322: Обратная итерация

Новая встроенная функция reversed(seq) принимает последовательность и возвращает итератор, который перебирает элементы последовательности в обратном порядке.

>>> for i in reversed(xrange(1,4)):
...    print i
...
3
2
1

По сравнению с расширенными срезами, такими как range(1,4)[::-1], reversed() легче читается, работает быстрее и использует значительно меньше памяти.

Обратите внимание, что reversed() принимает только последовательности, а не произвольные итераторы. Если вы хотите обратить итератор, сначала преобразуйте его в список с помощью list().

>>> input = open('/etc/passwd', 'r')
>>> for line in reversed(list(input)):
...   print line
...
root:*:0:0:System Administrator:/var/root:/bin/tcsh
  ...

См.также

PEP 322 - Обратная итерация

Написано и реализовано Раймондом Хеттингером.

PEP 324: Новый подпроцесс Модуль

Стандартная библиотека предоставляет несколько способов выполнения подпроцесса, предлагающих различные возможности и разные уровни сложности. Модуль os.system(command) прост в использовании, но медлителен (он запускает процесс оболочки, который выполняет команду) и опасен (нужно быть осторожным с экранированием метасимволов оболочки). Модуль popen2 предлагает классы, которые могут перехватывать стандартный вывод и стандартную ошибку из подпроцесса, но их именование сбивает с толку. Модуль subprocess устраняет эту путаницу, предоставляя единый интерфейс, который предлагает все необходимые функции.

Вместо коллекции классов popen2 в subprocess содержится один класс subprocess.Popen, конструктор которого поддерживает несколько различных ключевых аргументов.

class Popen(args, bufsize=0, executable=None,
            stdin=None, stdout=None, stderr=None,
            preexec_fn=None, close_fds=False, shell=False,
            cwd=None, env=None, universal_newlines=False,
            startupinfo=None, creationflags=0):

args - это последовательность строк, которые будут аргументами программы, выполняемой в качестве подпроцесса. (Если аргумент shell равен true, args может быть строкой, которая затем будет передана оболочке для интерпретации, как это делает os.system()).

stdin, stdout и stderr указывают, какими будут потоки ввода, вывода и ошибок подпроцесса. Вы можете указать объект файла или дескриптор файла, или использовать константу subprocess.PIPE для создания канала между подпроцессом и родителем.

Конструктор имеет ряд удобных опций:

  • close_fds запрашивает закрытие всех файловых дескрипторов перед запуском подпроцесса.

  • cwd задает рабочий каталог, в котором будет выполняться подпроцесс (по умолчанию это рабочий каталог родителя).

  • env - это словарь, определяющий переменные окружения.

  • preexec_fn - это функция, которая вызывается перед запуском ребенка.

  • universal_newlines открывает вход и выход дочернего файла, используя функцию Python universal newlines.

Создав экземпляр Popen, вы можете вызвать его метод wait(), чтобы сделать паузу до завершения подпроцесса, poll(), чтобы проверить, завершился ли он без паузы, или communicate(data), чтобы отправить строку data на стандартный вход подпроцесса. Затем communicate(data) считывает все данные, которые подпроцесс отправил на стандартный вывод или стандартную ошибку, возвращая кортеж (stdout_data, stderr_data).

call() - это ярлык, который передает свои аргументы конструктору Popen, ожидает завершения команды и возвращает код состояния подпроцесса. Он может служить более безопасным аналогом os.system():

sts = subprocess.call(['dpkg', '-i', '/tmp/new-package.deb'])
if sts == 0:
    # Success
    ...
else:
    # dpkg returned an error
    ...

Команда вызывается без использования оболочки. Если вы действительно хотите использовать оболочку, вы можете добавить shell=True в качестве аргумента ключевого слова и указать строку вместо последовательности:

sts = subprocess.call('dpkg -i /tmp/new-package.deb', shell=True)

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

См.также

PEP 324 - subprocess - модуль нового процесса

Написано и реализовано Петером Острандом при содействии Фредрика Лунда и других.

PEP 327: Десятичный тип данных

Python всегда поддерживал в качестве типа данных числа с плавающей точкой (FP), основанные на базовом типе C double. Однако, хотя большинство языков программирования предоставляют тип с плавающей точкой, многие люди (даже программисты) не знают, что числа с плавающей точкой не могут точно представлять некоторые десятичные дроби. Новый тип Decimal может точно представлять эти дроби, вплоть до заданного пользователем предела точности.

Зачем нужна десятичная дробь?

Ограничения возникают из-за представления, используемого для чисел с плавающей точкой. Числа с плавающей запятой состоят из трех компонентов:

  • Знак, положительный или отрицательный.

  • Мантисса, которая представляет собой одноразрядное двоичное число, за которым следует дробная часть. Например, 1.01 в системе счисления base-2 - это 1 + 0/2 + 1/4, или 1,25 в десятичной системе счисления.

  • Экспонента, которая указывает, где находится десятичная точка в представленном числе.

Например, число 1,25 имеет положительный знак, значение мантиссы 1,01 (в двоичном исчислении) и экспоненту 0 (десятичную точку не нужно сдвигать). Число 5 имеет тот же знак и мантиссу, но экспонента равна 2, потому что мантисса умножается на 4 (2 в степени экспоненты 2); 1,25 * 4 равно 5.

Современные системы обычно обеспечивают поддержку плавающей точки в соответствии со стандартом IEEE 754. Тип double в языке C обычно реализуется как 64-битное число IEEE 754, которое использует 52 бита пространства для мантиссы. Это означает, что числа могут быть заданы только с точностью до 52 бит. Если вы пытаетесь представить число, расширение которого повторяется бесконечно, то расширение обрывается после 52 бит. К сожалению, большинство программ должны выдавать результаты по основанию 10, а обычные дроби по основанию 10 часто повторяют десятичные числа в двоичном исчислении. Например, 1,1 десятичной дроби - это двоичная 1.0001100110011 ...; .1 = 1/16 + 1/32 + 1/256 плюс бесконечное число дополнительных членов. В стандарте IEEE 754 приходится обрывать эту бесконечно повторяющуюся десятичную дробь после 52 цифр, поэтому представление получается немного неточным.

Иногда эту неточность можно заметить при выводе номера на печать:

>>> 1.1
1.1000000000000001

Неточность не всегда видна при выводе числа на печать, потому что преобразование FP в десятичную строку обеспечивается библиотекой C, а большинство библиотек C стараются выдавать разумные результаты. Однако даже если она не отображается, неточность все равно остается, и последующие операции могут увеличить ошибку.

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

Таким образом, был создан тип Decimal.

Тип Decimal

В стандартную библиотеку Python был добавлен новый модуль decimal. Он содержит два класса, Decimal и Context. Экземпляры Decimal представляют числа, а экземпляры Context используются для обертывания различных настроек, таких как точность и режим округления по умолчанию.

Экземпляры Decimal неизменяемы, как обычные целые числа Python и числа FP; после их создания вы не сможете изменить значение, которое представляет экземпляр. Экземпляры Decimal могут быть созданы из целых чисел или строк:

>>> import decimal
>>> decimal.Decimal(1972)
Decimal("1972")
>>> decimal.Decimal("1.1")
Decimal("1.1")

Вы также можете предоставить кортежи, содержащие знак, мантиссу, представленную в виде кортежа десятичных цифр, и экспоненту:

>>> decimal.Decimal((1, (1, 4, 7, 5), -2))
Decimal("-14.75")

Внимание: бит sign является булевым значением, поэтому 0 означает положительное значение, а 1 - отрицательное.

Преобразование чисел с плавающей запятой создает некоторую проблему: должно ли число FP, представляющее 1,1, превратиться в десятичное число ровно для 1,1 или для 1,1 плюс любые вносимые неточности? Было принято решение уклониться от решения этой проблемы и оставить такое преобразование за пределами API. Вместо этого следует преобразовать число с плавающей запятой в строку с требуемой точностью и передать строку в конструктор Decimal:

>>> f = 1.1
>>> decimal.Decimal(str(f))
Decimal("1.1")
>>> decimal.Decimal('%.12f' % f)
Decimal("1.100000000000")

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

>>> a = decimal.Decimal('35.72')
>>> b = decimal.Decimal('1.73')
>>> a+b
Decimal("37.45")
>>> a-b
Decimal("33.99")
>>> a*b
Decimal("61.7956")
>>> a/b
Decimal("20.64739884393063583815028902")
>>> a ** 2
Decimal("1275.9184")
>>> a**b
Traceback (most recent call last):
  ...
decimal.InvalidOperation: x ** (non-integer)

Вы можете комбинировать экземпляры Decimal с целыми числами, но не с числами с плавающей точкой:

>>> a + 4
Decimal("39.72")
>>> a + 4.5
Traceback (most recent call last):
  ...
TypeError: You can interact Decimal only with int, long or Decimal data types.
>>>

Числа Decimal можно использовать с модулями math и cmath, но учтите, что перед выполнением операции они будут немедленно преобразованы в числа с плавающей точкой, что приведет к возможной потере точности и аккуратности. Кроме того, вы получите в ответ обычное число с плавающей точкой, а не Decimal.

>>> import math, cmath
>>> d = decimal.Decimal('123456789012.345')
>>> math.sqrt(d)
351364.18288201344
>>> cmath.sqrt(-d)
351364.18288201344j

У экземпляров Decimal есть метод sqrt(), который возвращает Decimal, но если вам нужны другие вещи, такие как тригонометрические функции, вам придется их реализовать.

>>> d.sqrt()
Decimal("351364.1828820134592177245001")

Тип Context

Экземпляры класса Context содержат несколько настроек для десятичных операций:

  • prec - это точность, количество знаков после запятой.

  • Модуль rounding задает режим округления. Модуль decimal содержит константы для различных вариантов: ROUND_DOWN, ROUND_CEILING, ROUND_HALF_EVEN и другие.

  • traps - это словарь, определяющий, что происходит при возникновении определенных условий ошибки: либо возбуждается исключение, либо возвращается значение. Примерами ошибок являются деление на ноль, потеря точности и переполнение.

Локальный контекст по умолчанию доступен по вызову getcontext(); вы можете изменить свойства этого контекста, чтобы изменить точность, округление или обработку ловушек по умолчанию. В следующем примере показан эффект изменения точности контекста по умолчанию:

>>> decimal.getcontext().prec
28
>>> decimal.Decimal(1) / decimal.Decimal(7)
Decimal("0.1428571428571428571428571429")
>>> decimal.getcontext().prec = 9
>>> decimal.Decimal(1) / decimal.Decimal(7)
Decimal("0.142857143")

Действие по умолчанию для условий ошибки можно выбрать; модуль может либо вернуть специальное значение, такое как бесконечность или not-a-number, либо поднять исключения:

>>> decimal.Decimal(1) / decimal.Decimal(0)
Traceback (most recent call last):
  ...
decimal.DivisionByZero: x / 0
>>> decimal.getcontext().traps[decimal.DivisionByZero] = False
>>> decimal.Decimal(1) / decimal.Decimal(0)
Decimal("Infinity")
>>>

Экземпляр Context также имеет различные методы форматирования чисел, такие как to_eng_string() и to_sci_string().

Для получения дополнительной информации см. документацию по модулю decimal, которая включает в себя краткое руководство и справочник.

См.также

PEP 327 - Десятичный тип данных

Автор сценария - Факундо Батиста, а воплотили его в жизнь Факундо Батиста, Эрик Прайс, Раймонд Хеттингер, Аахз и Тим Питерс.

http://www.lahey.com/float.htm

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

http://speleotrove.com/decimal/

Описание десятичного представления. Это представление предлагается в качестве стандарта и лежит в основе нового десятичного типа Python. Большая часть этого материала была написана Майком Каулишоу, разработчиком языка Rexx.

PEP 328: Многострочный импорт

Одно из изменений в языке - небольшая синтаксическая правка, направленная на упрощение импорта многих имен из модуля. В операторе from module import names names - это последовательность имен, разделенных запятыми. Если последовательность очень длинная, вы можете либо написать несколько импортов из одного модуля, либо использовать обратные косые черты для экранирования окончаний строк, например, так:

from SimpleXMLRPCServer import SimpleXMLRPCServer,\
            SimpleXMLRPCRequestHandler,\
            CGIXMLRPCRequestHandler,\
            resolve_dotted_attribute

Синтаксическое изменение в Python 2.4 просто позволяет помещать имена в круглые скобки. Python игнорирует новые строки внутри выражения, заключенного в круглые скобки, поэтому обратные слеши больше не нужны:

from SimpleXMLRPCServer import (SimpleXMLRPCServer,
                                SimpleXMLRPCRequestHandler,
                                CGIXMLRPCRequestHandler,
                                resolve_dotted_attribute)

В PEP также предлагается, чтобы все операторы import были абсолютным импортом, а символ . указывал на относительный импорт. Эта часть PEP не была реализована в Python 2.4, но была завершена в Python 2.5.

См.также

PEP 328 - Импорт: Многострочный и абсолютный/относительный

Автор Aahz. Многострочный импорт был реализован Димой Дорфманом.

PEP 331: Локально-зависимые преобразования плавающей/строчной величины

Модуль locale позволяет программам Python выбирать различные преобразования и соглашения об отображении, локализованные для конкретной страны или языка. Однако модуль старался не изменять числовую локаль, поскольку различные функции в реализации Python требовали, чтобы числовая локаль оставалась установленной на локаль 'C'. Часто это происходило потому, что в коде использовалась функция atof() библиотеки C.

Однако отказ от установки числовой локали создавал проблемы для расширений, использующих сторонние библиотеки C, поскольку в них не устанавливалась правильная локаль. В качестве примера можно привести GTK+, виджеты пользовательского интерфейса которого не отображали числа в текущей локали.

Решение, описанное в PEP, заключается в добавлении трех новых функций в Python API, которые выполняют преобразования только в ASCII, игнорируя настройки локали:

  • PyOS_ascii_strtod(str, ptr) и PyOS_ascii_atof(str, ptr) преобразуют строку в C double.

  • PyOS_ascii_formatd(buffer, buf_len, format, d) преобразует double в строку ASCII.

Код для этих функций был взят из библиотеки GLib (https://developer-old.gnome.org/glib/2.26/), разработчики которой любезно перелицензировали соответствующие функции и передали их в Python Software Foundation. Модуль locale теперь может изменять числовую локаль, позволяя таким расширениям, как GTK+, выдавать правильные результаты.

См.также

PEP 331 - Локально-зависимые преобразования плавающей/строчной величины

Автор сценария - Кристиан Р. Рейс, реализация - Густаво Карнейро.

Другие языковые изменения

Вот все изменения, которые Python 2.4 вносит в основной язык Python.

  • Добавлены декораторы для функций и методов (PEP 318).

  • Были добавлены встроенные типы set() и frozenset() (PEP 218). Среди других новых встроенных типов - функция reversed(seq) (PEP 322).

  • Добавлены выражения-генераторы (PEP 289).

  • Некоторые числовые выражения больше не возвращают значения, ограниченные 32 или 64 битами (PEP 237).

  • Теперь вы можете заключить в круглые скобки список имен в операторе from module import names (PEP 328).

  • Метод dict.update() теперь принимает те же формы аргументов, что и конструктор dict. Сюда входят любые отображения, любые итерации пар ключ/значение, а также аргументы в виде ключевых слов. (Внесено Раймондом Хеттингером).

  • Строковые методы ljust(), rjust() и center() теперь принимают необязательный аргумент для указания символа заполнения, отличного от пробела. (Внесено Раймондом Хеттингером).

  • В строках также появился метод rsplit(), который работает так же, как метод split(), но отделяет от конца строки. (Внесено Шоном Рейфшнайдером.)

    >>> 'www.python.org'.split('.', 1)
    ['www', 'python.org']
    'www.python.org'.rsplit('.', 1)
    ['www.python', 'org']
    
  • В метод списков sort() были добавлены три ключевых слова-параметра, cmp, key и reverse. Эти параметры упрощают некоторые распространенные варианты использования sort(). Все эти параметры являются необязательными.

    Для параметра cmp значение должно быть функцией сравнения, которая принимает два параметра и возвращает -1, 0 или +1 в зависимости от того, как сравниваются параметры. Эта функция будет использоваться для сортировки списка. Ранее это был единственный параметр, который можно было передать в sort().

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

    >>> L = ['A', 'b', 'c', 'D']
    >>> L.sort()                 # Case-sensitive sort
    >>> L
    ['A', 'D', 'b', 'c']
    >>> # Using 'key' parameter to sort list
    >>> L.sort(key=lambda x: x.lower())
    >>> L
    ['A', 'b', 'c', 'D']
    >>> # Old-fashioned way
    >>> L.sort(cmp=lambda x,y: cmp(x.lower(), y.lower()))
    >>> L
    ['A', 'b', 'c', 'D']
    

    Последний пример, в котором используется параметр cmp, - это старый способ выполнения сортировки без учета регистра. Он работает, но медленнее, чем использование параметра key. При использовании key метод lower() вызывается один раз для каждого элемента списка, в то время как при использовании cmp он будет вызываться дважды для каждого сравнения, поэтому использование key позволяет сэкономить на вызове метода lower().

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

    >>> L.sort(key=str.lower)
    >>> L
    ['A', 'b', 'c', 'D']
    

    Наконец, параметр reverse принимает булево значение. Если значение равно true, список будет отсортирован в обратном порядке. Вместо L.sort(); L.reverse() теперь можно написать L.sort(reverse=True).

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

    (Все изменения в sort() внесены Раймондом Хеттингером).

  • Появилась новая встроенная функция sorted(iterable), которая работает как метод in-place list.sort(), но может использоваться в выражениях. Различия заключаются в следующем:

  • входом может быть любая итерируемая переменная;

  • вновь сформированная копия сортируется, оставляя оригинал нетронутым; и

  • выражение возвращает новую отсортированную копию

    >>> L = [9,7,8,3,2,4,1,6,5]
    >>> [10+i for i in sorted(L)]       # usable in a list comprehension
    [11, 12, 13, 14, 15, 16, 17, 18, 19]
    >>> L                               # original is left unchanged
    [9,7,8,3,2,4,1,6,5]
    >>> sorted('Monty Python')          # any iterable may be an input
    [' ', 'M', 'P', 'h', 'n', 'n', 'o', 'o', 't', 't', 'y', 'y']
    
    >>> # List the contents of a dict sorted by key values
    >>> colormap = dict(red=1, blue=2, green=3, black=4, yellow=5)
    >>> for k, v in sorted(colormap.iteritems()):
    ...     print k, v
    ...
    black 4
    blue 2
    green 3
    red 1
    yellow 5
    

    (Предоставлено Раймондом Хеттингером.)

  • Целочисленные операции больше не будут вызывать ошибку OverflowWarning. Предупреждение OverflowWarning исчезнет в Python 2.5.

  • В интерпретаторе появился новый переключатель -m, который принимает имя, ищет соответствующий модуль на sys.path и запускает модуль как сценарий. Например, с помощью python -m profile теперь можно запустить профилировщик Python. (Внесено Ником Когланом.)

  • Функции eval(expr, globals, locals) и execfile(filename, globals, locals), а также оператор exec теперь принимают любой тип отображения для параметра locals. Ранее это должен был быть обычный словарь Python. (Внесено Раймондом Хеттингером).

  • Встроенная функция zip() и itertools.izip() теперь возвращают пустой список, если вызываются без аргументов. Ранее они вызывали исключение TypeError. Это делает их более подходящими для использования со списками аргументов переменной длины:

    >>> def transpose(array):
    ...    return zip(*array)
    ...
    >>> transpose([(1,2,3), (4,5,6)])
    [(1, 4), (2, 5), (3, 6)]
    >>> transpose([])
    []
    

    (Предоставлено Раймондом Хеттингером.)

  • Если при импорте модуля произошел сбой, больше не нужно оставлять частично инициализированный объект модуля в sys.modules. Оставшийся неполный объект модуля мог обмануть последующие импорты того же модуля, что приводило к запутанным ошибкам. (Исправлено Тимом Питерсом).

  • None теперь является константой; код, привязывающий новое значение к имени None, теперь является синтаксической ошибкой. (Внесено Раймондом Хеттингером.)

Оптимизации

  • Внутренние циклы для нарезки списков и кортежей были оптимизированы и теперь работают примерно на треть быстрее. Внутренние циклы для словарей также были оптимизированы, что привело к увеличению производительности для keys(), values(), items(), iterkeys(), itervalues() и iteritems(). (Внесено Раймондом Хеттингером.)

  • Механизм увеличения и уменьшения списков был оптимизирован для повышения скорости и экономии места. Добавление и извлечение из списков теперь выполняется быстрее благодаря более эффективным путям кода и менее частому использованию базовой системы realloc(). Понимание списков также выигрывает. list.extend() также был оптимизирован и больше не преобразует свой аргумент во временный список перед расширением базового списка. (Внесено Раймондом Хеттингером).

  • list(), tuple(), map(), filter() и zip() теперь работают в несколько раз быстрее с непоследовательными аргументами, которые предоставляют метод __len__(). (Внесено Раймондом Хеттингером).

  • Методы list.__getitem__(), dict.__getitem__() и dict.__contains__() теперь реализованы как объекты method_descriptor, а не wrapper_descriptor. Такая форма доступа удваивает их производительность и делает их более подходящими для использования в качестве аргументов функций: map(mydict.__getitem__, keylist). (Внесено Раймондом Хеттингером.)

  • Добавлен новый опкод, LIST_APPEND, который упрощает генерируемый байткод для вычислений списков и ускоряет их примерно на треть. (Внесено Раймондом Хеттингером).

  • Оптимизатор байткода peephole был улучшен для создания более короткого и быстрого байткода; примечательно, что полученный байткод стал более читабельным. (Улучшено Раймондом Хеттингером).

  • Конкатенация строк в операторах вида s = s + "abc" и s += "abc" теперь выполняется более эффективно в определенных обстоятельствах. Эта оптимизация не будет присутствовать в других реализациях Python, таких как Jython, поэтому не стоит полагаться на нее; использование метода join() для строк по-прежнему рекомендуется, когда вы хотите эффективно склеить большое количество строк вместе. (Внесено Армином Риго.)

В результате оптимизации в версии 2.4 Python 2.4 работает в бенчмарке pystone примерно на 5% быстрее, чем Python 2.3, и на 35% быстрее, чем Python 2.2. (pystone - не особенно хороший бенчмарк, но это наиболее часто используемый показатель производительности Python. Ваши собственные приложения могут показать больший или меньший выигрыш от Python 2.4).

Новые, улучшенные и устаревшие модули

Как обычно, стандартная библиотека Python получила ряд улучшений и исправлений ошибок. Здесь представлен неполный список наиболее заметных изменений, отсортированный в алфавитном порядке по имени модуля. За более полным списком изменений обратитесь к файлу Misc/NEWS в дереве исходных текстов или просмотрите журналы CVS, чтобы узнать все подробности.

  • Функция asyncore модуля loop() теперь имеет параметр count, позволяющий выполнить ограниченное количество проходов через цикл опроса. По умолчанию цикл по-прежнему выполняется вечно.

  • Модуль base64 теперь имеет более полную поддержку RFC 3548 для кодирования и декодирования Base64, Base32 и Base16, включая опциональное сложение регистра и опциональные альтернативные алфавиты. (Внесено Барри Варшавой.)

  • Модуль bisect теперь имеет реализацию на языке C для повышения производительности. (Внесено Дмитрием Васильевым.)

  • Коллекция восточноазиатских кодеков CJKCodecs, поддерживаемая Hye-Shik Chang, была интегрирована в 2.4. Новыми кодировками являются:

  • Китайский (КНР): gb2312, gbk, gb18030, big5hkscs, hz

  • Китайский язык (ROC): big5, cp950

  • Японский: cp932, euc-jis-2004, euc-jp, euc-jisx0213, iso-2022-jp,

    iso-2022-jp-1, iso-2022-jp-2, iso-2022-jp-3, iso-2022-jp-ext, iso-2022-jp-2004, shift-jis, shift-jisx0213, shift-jis-2004

  • Корейский: cp949, euc-kr, johab, iso-2022-kr

  • Были добавлены некоторые другие новые кодировки: HP Roman8, ISO_8859-11, ISO_8859-16, PCTP-154 и TIS-620.

  • Кодеки UTF-8 и UTF-16 теперь лучше справляются с получением частичного ввода. Раньше класс StreamReader пытался прочитать больше данных, что делало невозможным возобновление декодирования из потока. Теперь метод read() будет возвращать столько данных, сколько сможет, и последующие вызовы возобновят декодирование с того места, на котором остановились предыдущие. (Реализовано Вальтером Дёрвальдом).

  • Появился новый модуль collections для различных специализированных типов данных коллекции. В настоящее время он содержит только один тип, deque, двустороннюю очередь, которая поддерживает эффективное добавление и удаление элементов с обоих концов:

    >>> from collections import deque
    >>> d = deque('ghi')        # make a new deque with three items
    >>> d.append('j')           # add a new entry to the right side
    >>> d.appendleft('f')       # add a new entry to the left side
    >>> d                       # show the representation of the deque
    deque(['f', 'g', 'h', 'i', 'j'])
    >>> d.pop()                 # return and remove the rightmost item
    'j'
    >>> d.popleft()             # return and remove the leftmost item
    'f'
    >>> list(d)                 # list the contents of the deque
    ['g', 'h', 'i']
    >>> 'h' in d                # search the deque
    True
    

    Некоторые модули, такие как модули Queue и threading, теперь используют преимущества collections.deque для повышения производительности. (Внесено Раймондом Хеттингером).

  • Классы ConfigParser были немного улучшены. Метод read() теперь возвращает список файлов, которые были успешно разобраны, а метод set() вызывает ошибку TypeError, если передан аргумент значение, не являющийся строкой. (Вклад внесли Джон Белмонте и Дэвид Гуджер).

  • Модуль curses теперь поддерживает расширение ncurses use_default_colors(). На платформах, где терминал поддерживает прозрачность, это позволяет использовать прозрачный фон. (Внесено Йоргом Леманном).

  • Модуль difflib теперь включает класс HtmlDiff, который создает HTML-таблицу, показывающую боковое сравнение двух версий текста. (Внесено Дэном Гассом).

  • Пакет email был обновлен до версии 3.0, в которой были исключены различные устаревшие API и удалена поддержка версий Python ранее 2.3. В версии 3.0 используется новый инкрементный парсер для MIME-сообщений, доступный в модуле email.FeedParser. Новый парсер не требует чтения всего сообщения в память и не вызывает исключений, если сообщение неправильно сформировано; вместо этого он записывает все проблемы в атрибут defect сообщения. (Разработан Энтони Бакстером, Барри Варшавой, Томасом Воутерсом и другими).

  • Модуль heapq был переведен на язык C. Благодаря десятикратному увеличению скорости модуль подходит для работы с большими объемами данных. Кроме того, в модуле появились две новые функции nlargest() и nsmallest(), которые используют кучи для поиска N наибольших или наименьших значений в наборе данных без затрат на полную сортировку. (Внесено Раймондом Хеттингером).

  • Модуль httplib теперь содержит константы для кодов состояния HTTP, определенных в различных документах RFC, связанных с HTTP. Константы имеют такие имена, как OK, CREATED, CONTINUE и MOVED_PERMANENTLY; используйте pydoc для получения полного списка. (Внесено Эндрю Эландом.)

  • Модуль imaplib теперь поддерживает команду IMAP THREAD (вклад Ива Дионна) и новые методы deleteacl() и myrights() (вклад Арно Мазина).

  • Модуль itertools получил функцию groupby(iterable[, *func*]). iterable - это то, что можно итерировать, чтобы вернуть поток элементов, а необязательный параметр func - это функция, которая принимает элемент и возвращает значение ключа; если он опущен, то ключом является просто сам элемент. groupby() группирует элементы в подпоследовательности, которые имеют совпадающие значения ключа, и возвращает серию из 2 кортежей, содержащих значение ключа и итератор по подпоследовательности.

    Приведем пример, чтобы сделать это более понятным. Функция key просто возвращает, является ли число четным или нечетным, поэтому результат groupby() возвращает последовательный ряд четных или нечетных чисел.

    >>> import itertools
    >>> L = [2, 4, 6, 7, 8, 9, 11, 12, 14]
    >>> for key_val, it in itertools.groupby(L, lambda x: x % 2):
    ...    print key_val, list(it)
    ...
    0 [2, 4, 6]
    1 [7]
    0 [8]
    1 [9, 11]
    0 [12, 14]
    >>>
    

    groupby() обычно используется при сортировке входных данных. Логика работы groupby() аналогична фильтру Unix uniq, что делает его удобным для устранения, подсчета или выявления дублирующихся элементов:

    >>> word = 'abracadabra'
    >>> letters = sorted(word)   # Turn string into a sorted list of letters
    >>> letters
    ['a', 'a', 'a', 'a', 'a', 'b', 'b', 'c', 'd', 'r', 'r']
    >>> for k, g in itertools.groupby(letters):
    ...    print k, list(g)
    ...
    a ['a', 'a', 'a', 'a', 'a']
    b ['b', 'b']
    c ['c']
    d ['d']
    r ['r', 'r']
    >>> # List unique letters
    >>> [k for k, g in groupby(letters)]
    ['a', 'b', 'c', 'd', 'r']
    >>> # Count letter occurrences
    >>> [(k, len(list(g))) for k, g in groupby(letters)]
    [('a', 5), ('b', 2), ('c', 1), ('d', 1), ('r', 2)]
    

    (Предоставлено Hye-Shik Chang.)

  • В itertools также появилась функция tee(iterator, N), которая возвращает N независимых итераторов, повторяющих iterator. Если N опущено, по умолчанию используется значение 2.

    >>> L = [1,2,3]
    >>> i1, i2 = itertools.tee(L)
    >>> i1,i2
    (<itertools.tee object at 0x402c2080>, <itertools.tee object at 0x402c2090>)
    >>> list(i1)               # Run the first iterator to exhaustion
    [1, 2, 3]
    >>> list(i2)               # Run the second iterator to exhaustion
    [1, 2, 3]
    

    Обратите внимание, что tee() должен хранить копии значений, возвращаемых итератором; в худшем случае ему может потребоваться хранить их все. Поэтому его следует использовать с осторожностью, если ведущий итератор может сильно опередить отстающий итератор в длинном потоке входных данных. Если разделение велико, то вместо него можно использовать list(). Если итераторы идут вплотную друг к другу, идеальным вариантом будет tee(). Возможные применения: закладка, оконные итераторы или итераторы с опережением. (Внесено Раймондом Хеттингером.)

  • В модуль locale был добавлен ряд функций, таких как bind_textdomain_codeset() для указания конкретной кодировки и семейство функций l*gettext(), возвращающих сообщения в выбранной кодировке. (Внесено Густаво Нимейером.)

  • Для упрощения настройки журнала в функцию basicConfig() пакета logging были добавлены некоторые аргументы с ключевыми словами. По умолчанию сообщения записываются в стандартную ошибку, но можно указать различные ключевые слова для записи в определенный файл, изменения формата записи в журнал или установки уровня записи в журнал. Например:

    import logging
    logging.basicConfig(filename='/var/log/application.log',
        level=0,  # Log all messages
        format='%(levelname):%(process):%(thread):%(message)')
    

    Другие дополнения к пакету logging включают в себя метод удобства log(level, msg), а также класс TimedRotatingFileHandler, который поворачивает файлы журналов через определенный интервал времени. В модуле уже был RotatingFileHandler, который поворачивал журналы, когда файл превышал определенный размер. Оба класса являются производными от нового класса BaseRotatingHandler, который может быть использован для реализации других обработчиков ротации.

    (Изменения внесены Винаем Саджипом).

  • Модуль marshal теперь разделяет интернированные строки при распаковке структуры данных. Это может уменьшить размер некоторых строк pickle, но основной эффект заключается в том, что файлы .pyc стали значительно меньше. (Внесено Мартином фон Лёвисом).

  • Класс NNTP модуля nntplib получил методы description() и descriptions() для получения описаний групп новостей для одной группы или для ряда групп. (Внесено Юргеном А. Эрхардом).

  • В модуль operator были добавлены две новые функции, attrgetter(attr) и itemgetter(index). Обе функции возвращают вызываемые переменные, которые принимают один аргумент и возвращают соответствующий атрибут или элемент; эти вызываемые переменные являются отличными экстракторами данных при использовании с map() или sorted(). Например:

    >>> L = [('c', 2), ('d', 1), ('a', 4), ('b', 3)]
    >>> map(operator.itemgetter(0), L)
    ['c', 'd', 'a', 'b']
    >>> map(operator.itemgetter(1), L)
    [2, 1, 4, 3]
    >>> sorted(L, key=operator.itemgetter(1)) # Sort list by second tuple item
    [('d', 1), ('c', 2), ('b', 3), ('a', 4)]
    

    (Предоставлено Раймондом Хеттингером.)

  • Модуль optparse был обновлен различными способами. Теперь модуль передает свои сообщения через gettext.gettext(), что позволяет интернационализировать справку и сообщения об ошибках Optik. Справочные сообщения для опций теперь могут включать строку '%default', которая будет заменена значением опции по умолчанию. (Внесено Грегом Уордом.)

  • В долгосрочной перспективе планируется отказаться от модуля rfc822 в одном из будущих выпусков Python в пользу пакета email. С этой целью функция email.Utils.formatdate была изменена, чтобы сделать ее пригодной для замены rfc822.formatdate(). Возможно, вы захотите написать новый код обработки электронной почты с учетом этого. (Изменения внесены Энтони Бакстером).

  • В модуль os была добавлена новая функция urandom(n), возвращающая строку, содержащую n байт случайных данных. Эта функция обеспечивает доступ к источникам случайных данных для конкретной платформы, таким как /dev/urandom в Linux или CryptoAPI для Windows. (Внесено Тревором Перрином).

  • Еще одна новая функция: os.path.lexists(path) возвращает true, если файл, указанный path, существует, независимо от того, является ли он символической ссылкой или нет. Это отличается от существующей функции os.path.exists(path), которая возвращает false, если path является символической ссылкой, указывающей на несуществующее место назначения. (Внесено Бени Чернявским.)

  • В модуль posix была добавлена новая функция getsid(), которая лежит в основе модуля os. (Внесено Дж. Рейнором).

  • Модуль poplib теперь поддерживает POP через SSL. (Внесено Гектором Уртубиа.)

  • Модуль profile теперь может профилировать функции расширения C. (Внесено Ником Бастином.)

  • В модуле random появился новый метод getrandbits(N), который возвращает длинное целое число длиной N бит. Существующий метод randrange() теперь использует getrandbits() там, где это необходимо, что делает генерацию произвольно больших случайных чисел более эффективной. (Внесено Раймондом Хеттингером).

  • Язык регулярных выражений, принятый в модуле re, был расширен простыми условными выражениями, которые записываются в виде (?(group)A|B). group - это либо числовой идентификатор группы, либо имя группы, заданное с помощью (?P<group>...) ранее в выражении. Если указанная группа совпала, то шаблон регулярного выражения A будет проверен на соответствие строке; если группа не совпала, то вместо нее будет использован шаблон B. (Внесено Густаво Нимейером).

  • Модуль re также больше не является рекурсивным, благодаря огромной работе Густаво Нимейера. В рекурсивном механизме регулярных выражений некоторые шаблоны занимают большое количество места в стеке C, что приводило к переполнению стека. Например, если сопоставить 30000-байтную строку из символов a с выражением (a|b)+, то на каждый символ приходилось по одному кадру стека. Python 2.3 пытался проверить переполнение стека и вызвать исключение RuntimeError, но некоторые шаблоны могли обойти проверку, и если вам не везло, Python мог сбиться в сегфолт. Механизм регулярных выражений Python 2.4 без проблем подбирает этот шаблон.

  • Модуль signal теперь более тщательно проверяет параметры функции signal.signal() на наличие ошибок. Например, вы не можете установить обработчик на сигнал SIGKILL; предыдущие версии Python спокойно принимали это, но 2.4 вызовет исключение RuntimeError.

  • В модуль socket были добавлены две новые функции. socketpair() возвращает пару соединенных сокетов, а getservbyport(port) ищет имя сервиса для заданного номера порта. (Вклад внесли Дэйв Коул и Барри Варшава).

  • Функция sys.exitfunc() была устаревшей. Код должен использовать существующий модуль atexit, который корректно обрабатывает вызов нескольких функций выхода. Со временем sys.exitfunc() станет чисто внутренним интерфейсом, доступ к которому будет осуществляться только через atexit.

  • Модуль tarfile теперь по умолчанию генерирует tar-файлы в формате GNU. (Внесено Ларсом Густебелем).

  • Модуль threading теперь имеет элегантно простой способ поддержки потоково-локальных данных. Модуль содержит класс local, значения атрибутов которого локальны для разных потоков.

    import threading
    
    data = threading.local()
    data.number = 42
    data.url = ('www.python.org', 80)
    

    Другие потоки могут присваивать и получать свои собственные значения для атрибутов number и url. Вы можете создать подкласс local, чтобы инициализировать атрибуты или добавить методы. (Внесено Джимом Фултоном.)

  • Модуль timeit теперь автоматически отключает периодическую сборку мусора во время цикла тайминга. Это изменение делает последовательные тайминги более сопоставимыми. (Внесено Раймондом Хеттингером).

  • Модуль weakref теперь поддерживает более широкий спектр объектов, включая функции Python, экземпляры классов, множества, фростенсеты, деки, массивы, файлы, сокеты и объекты шаблонов регулярных выражений. (Внесено Раймондом Хеттингером).

  • Модуль xmlrpclib теперь поддерживает расширение multi-call для передачи нескольких вызовов XML-RPC в одной операции HTTP. (Внесено Брайаном Куинланом).

  • Модули mpz, rotor и xreadlines были удалены.

cookielib

Библиотека cookielib поддерживает обработку HTTP-куки на стороне клиента, зеркально отражая поддержку куки на стороне сервера в модуле Cookie. Cookies хранятся в банках cookie; библиотека прозрачно сохраняет cookie, предлагаемые веб-сервером, в банке cookie и извлекает cookie из банка при подключении к серверу. Как и в веб-браузерах, объекты политики управляют принятием или непринятием файлов cookie.

Для хранения файлов cookie в разных сессиях предусмотрены две реализации куки-банков: одна хранит файлы cookie в формате Netscape, чтобы приложения могли использовать файлы cookie Mozilla или Lynx, а другая хранит файлы cookie в том же формате, что и библиотека Perl libwww.

urllib2 был изменен для взаимодействия с cookielib: HTTPCookieProcessor управляет банком cookie, который используется при доступе к URL-адресам.

Этот модуль был предоставлен Джоном Дж. Ли.

doctest

Модуль doctest подвергся значительному рефакторингу благодаря Эдварду Лоперу и Тиму Питерсу. Тестирование по-прежнему может быть простым, как запуск doctest.testmod(), но рефакторинг позволяет настраивать работу модуля различными способами

Новый класс DocTestFinder извлекает тесты из документальных строк объекта:

def f (x, y):
    """>>> f(2,2)
4
>>> f(3,2)
6
    """
    return x*y

finder = doctest.DocTestFinder()

# Get list of DocTest instances
tests = finder.find(f)

Новый класс DocTestRunner запускает отдельные тесты и может выдать сводку результатов:

runner = doctest.DocTestRunner()
for t in tests:
    tried, failed = runner.run(t)

runner.summarize(verbose=1)

Приведенный выше пример дает следующий результат:

1 items passed all tests:
   2 tests in f
2 tests in 1 items.
2 passed and 0 failed.
Test passed.

DocTestRunner использует экземпляр класса OutputChecker для сравнения ожидаемого и фактического результатов. Этот класс принимает несколько различных флагов, которые настраивают его поведение; амбициозные пользователи также могут написать совершенно новый подкласс OutputChecker.

Проверка вывода по умолчанию предоставляет ряд удобных функций. Например, при использовании флага doctest.ELLIPSIS многоточие (...) в ожидаемом выводе соответствует любой подстроке, что облегчает работу с выводами, которые отличаются незначительно:

def o (n):
    """>>> o(1)
<__main__.C instance at 0x...>
>>>
"""

Другая специальная строка, <BLANKLINE>, соответствует пустой строке:

def p (n):
    """>>> p(1)
<BLANKLINE>
>>>
"""

Еще одна новая возможность - отображение вывода в стиле diff с помощью флагов doctest.REPORT_UDIFF (unified diffs), doctest.REPORT_CDIFF (context diffs) или doctest.REPORT_NDIFF (delta-style). Например:

def g (n):
    """>>> g(4)
here
is
a
lengthy
>>>"""
    L = 'here is a rather lengthy list of words'.split()
    for word in L[:n]:
        print word

Запустив приведенные выше тесты функции с указанием doctest.REPORT_UDIFF, вы получите следующий результат:

**********************************************************************
File "t.py", line 15, in g
Failed example:
    g(4)
Differences (unified diff with -expected +actual):
    @@ -2,3 +2,3 @@
     is
     a
    -lengthy
    +rather
**********************************************************************

Изменения в сборке и C API

Некоторые из изменений в процессе сборки Python и в API C:

  • Добавлены три новых удобных макроса для обычных возвращаемых значений из функций расширения: Py_RETURN_NONE, Py_RETURN_TRUE и Py_RETURN_FALSE. (Внесено Бреттом Кэнноном.)

  • Еще один новый макрос, Py_CLEAR, уменьшает количество ссылок на obj и устанавливает obj в нулевой указатель. (Внесено Джимом Фултоном.)

  • Новая функция PyTuple_Pack(N, obj1, obj2, ..., objN) строит кортежи из списка аргументов переменной длины, состоящего из объектов Python. (Внесено Раймондом Хеттингером).

  • Новая функция PyDict_Contains(d, k) реализует быстрый поиск по словарю без маскировки исключений, возникающих в процессе поиска. (Вклад Раймонда Хеттингера).

  • Макрос Py_IS_NAN(X) возвращает 1, если его плавающий или двойной аргумент X является NaN. (Внесено Тимом Питерсом).

  • Код на языке Си может избежать ненужной блокировки, используя функцию new PyEval_ThreadsInitialized(), чтобы определить, были ли выполнены какие-либо операции с потоком. Если эта функция возвращает false, операции блокировки не нужны. (Вклад Ника Коглана.)

  • Новая функция, PyArg_VaParseTupleAndKeywords(), аналогична PyArg_ParseTupleAndKeywords(), но вместо нескольких аргументов принимает va_list. (Внесено Грегом Чепменом.)

  • Новый флаг метода, METH_COEXIST, позволяет функции, определенной в слотах, сосуществовать с PyCFunction, имеющим то же имя. Это может вдвое сократить время доступа к такому методу, как set.__contains__(). (Внесено Раймондом Хеттингером).

  • Теперь Python может быть собран с дополнительным профилированием самого интерпретатора, предназначенным для помощи людям, разрабатывающим ядро Python. Указание --enable-profiling в сценарии configure позволит вам профилировать интерпретатор с помощью gprof, а указание --with-tsc позволяет профилировать интерпретатор с помощью регистра Time-Stamp-Counter процессора Pentium. Обратите внимание, что переключатель --with-tsc немного неправильно назван, поскольку функция профилирования работает и на платформе PowerPC, хотя в этой процессорной архитектуре этот регистр не называется «регистром TSC». (Внесено Джереми Хилтоном.)

  • Тип tracebackobject был переименован в PyTracebackObject.

Изменения для конкретного порта

  • Порт для Windows теперь собирается как под MSVC++ 7.1, так и под версию 6. (Внесено Мартином фон Лёвисом.)

Переход на Python 2.4

В этом разделе перечислены ранее описанные изменения, которые могут потребовать внесения изменений в ваш код:

  • Слишком большие сдвиги влево и шестнадцатеричные/октальные константы больше не вызывают FutureWarning и не возвращают значение, ограниченное 32 или 64 битами; вместо этого они возвращают длинное целое число.

  • Целочисленные операции больше не будут вызывать ошибку OverflowWarning. Предупреждение OverflowWarning исчезнет в Python 2.5.

  • Встроенная функция zip() и itertools.izip() теперь возвращают пустой список, а не вызывают исключение TypeError при вызове без аргументов.

  • Вы больше не можете сравнивать экземпляры date и datetime, предоставляемые модулем datetime. Теперь два экземпляра разных классов всегда будут неравными, а относительные сравнения (<, >) будут вызывать ошибку TypeError.

  • dircache.listdir() теперь передает исключения вызывающей стороне, а не возвращает пустые списки.

  • LexicalHandler.startDTD() получал публичные и системные идентификаторы в неправильном порядке. Это исправлено; приложения, полагающиеся на неправильный порядок, должны быть исправлены.

  • fcntl.ioctl() теперь предупреждает, если аргумент mutate опущен и имеет значение.

  • Модуль tarfile теперь по умолчанию генерирует tar-файлы в формате GNU.

  • Сбой при импорте модуля больше не оставляет частично инициализированный объект модуля в sys.modules.

  • None теперь является константой; код, привязывающий новое значение к имени None, теперь является синтаксической ошибкой.

  • Функция signals.signal() теперь вызывает исключение RuntimeError для некоторых недопустимых значений; раньше эти ошибки проходили молча. Например, вы больше не можете установить обработчик на сигнал SIGKILL.

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

Автор хотел бы поблагодарить следующих людей за предложения, исправления и помощь в работе над различными вариантами этой статьи: Koray Can, Hye-Shik Chang, Michael Dyck, Raymond Hettinger, Brian Hurt, Hamish Lawson, Fredrik Lundh, Sean Reifschneider, Sadruddin Rejeb.