Что нового в 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. Реализация типов данных множеств на языке Си теперь добавлена в ядро 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, оценивая значение 0 на 32-битных платформах. В Python 2.4 это выражение теперь возвращает правильный ответ - 8589934592.

См.также

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

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

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

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

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 содержит один класс 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 в нотации основания-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 обычно реализуется как 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")

Внимание: бит знака является булевым значением, поэтому 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

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

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 - Импорт: Многострочный и абсолютный/относительный

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

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.gnome.org/glib/stable/), разработчики которой любезно перелицензировали соответствующие функции и передали их в 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']
    
  • Три параметра ключевых слов, cmp, key и reverse, были добавлены к методу списков sort(). Эти параметры упрощают некоторые распространенные случаи использования метода 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 с помощью python -m profile. (Внесено Ником Когланом.)

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

    Вот пример, чтобы сделать это более понятным. Функция 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)]
    

    (При участии Хье-Шик Чанга.)

  • 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(), возвращающих сообщения в выбранной кодировке. (Внесено Густаво Нимейером.)

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

    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 стали значительно меньше. (Внесено Мартином фон Лёвисом.)

  • Класс nntplib модуля NNTP получил методы 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(). Возможно, вы захотите написать новый код обработки электронной почты с учетом этого. (Изменение внесено Энтони Бакстером).

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

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

  • В модуль getsid(), который лежит в основе модуля posix, была добавлена новая функция 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.

Для того, чтобы хранить куки в разных сессиях, предусмотрены две реализации куки-банков: одна хранит куки в формате Netscape, чтобы приложения могли использовать файлы куки Mozilla или Lynx, а другая хранит куки в том же формате, что и библиотека 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>
>>>
"""

Еще одна новая возможность - это отображение вывода в стиле диффа путем указания флагов опций doctest.REPORT_UDIFF (унифицированные диффы), doctest.REPORT_CDIFF (контекстные диффы) или doctest.REPORT_NDIFF (дельта-стиль). Например:

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
**********************************************************************

Изменения в API Build и C

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

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

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

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

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

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

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

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

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

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