Что нового в Python 3.1¶
- Автор:
Раймонд Хеттингер
В этой статье рассказывается о новых возможностях Python 3.1 по сравнению с 3.0. Python 3.1 был выпущен 27 июня 2009 года.
PEP 372: Упорядоченные словари¶
Обычные словари Python перебирают пары ключ/значение в произвольном порядке. За прошедшие годы ряд авторов написали альтернативные реализации, которые запоминают порядок, в котором ключи были вставлены изначально. Основываясь на опыте этих реализаций, был введен новый класс collections.OrderedDict
.
API OrderedDict практически не отличается от обычных словарей, но перебирает ключи и значения в гарантированном порядке в зависимости от того, когда ключ был вставлен первым. Если новая запись перезаписывает существующую, исходная позиция вставки остается неизменной. Удаление записи и ее повторная вставка переместит ее в конец.
Стандартная библиотека теперь поддерживает использование упорядоченных словарей в нескольких модулях. Модуль configparser
использует их по умолчанию. Это позволяет читать, изменять и записывать конфигурационные файлы в исходном порядке. Метод _asdict() модуля collections.namedtuple()
теперь возвращает упорядоченный словарь, значения в котором располагаются в том же порядке, что и индексы кортежей. В модуль json
встраивается object_pairs_hook, чтобы декодер мог строить упорядоченные словари. Также была добавлена поддержка сторонних инструментов, таких как PyYAML.
См.также
- PEP 372 - Упорядоченные словари
PEP написан Армином Ронахером и Раймондом Хеттингером. Реализация написана Раймондом Хеттингером.
Поскольку упорядоченный словарь запоминает порядок вставки, его можно использовать в сочетании с сортировкой для создания отсортированного словаря:
>>> # regular unsorted dictionary
>>> d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}
>>> # dictionary sorted by key
>>> OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])
>>> # dictionary sorted by value
>>> OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])
>>> # dictionary sorted by length of the key string
>>> OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])
Новые отсортированные словари сохраняют порядок сортировки при удалении записей. Но когда добавляются новые ключи, они добавляются в конец, и сортировка не сохраняется.
PEP 378: Спецификатор формата для разделителя тысяч¶
Встроенная функция format()
и метод str.format()
используют мини-язык, который теперь включает простой, не зависящий от локали способ форматирования числа с разделителем тысяч. Это позволяет очеловечить вывод программы, улучшить его профессиональный вид и читабельность:
>>> format(1234567, ',d')
'1,234,567'
>>> format(1234567.89, ',.2f')
'1,234,567.89'
>>> format(12345.6 + 8901234.12j, ',f')
'12,345.600000+8,901,234.120000j'
>>> format(Decimal('1234567.89'), ',f')
'1,234,567.89'
Поддерживаются следующие типы: int
, float
, complex
и decimal.Decimal
.
В настоящее время обсуждается возможность указания альтернативных разделителей, таких как точки, пробелы, апострофы или символы подчеркивания. Локальные приложения должны использовать существующий спецификатор формата n, который уже имеет некоторую поддержку тысяч разделителей.
См.также
- PEP 378 - Спецификатор формата для разделителя тысяч
PEP написан Раймондом Хеттингером и реализован Эриком Смитом и Марком Дикинсоном.
Другие языковые изменения¶
Некоторые более мелкие изменения, внесенные в ядро языка Python:
Каталоги и zip-архивы, содержащие
__main__.py
файл, теперь можно выполнять напрямую, передавая их имя интерпретатору. Каталог/zip-файл автоматически вставляется в качестве первой записи в sys.path. (Предложение и первоначальный патч Энди Чу; исправленный патч Филлипа Дж. Эби и Ника Коглана; bpo-1739468).Тип
int()
получил методbit_length
, который возвращает количество битов, необходимых для представления аргумента в двоичном виде:>>> n = 37 >>> bin(37) '0b100101' >>> n.bit_length() 6 >>> n = 2**123-1 >>> n.bit_length() 123 >>> (n+1).bit_length() 124
(При участии Фредрика Йоханссона, Виктора Стиннера, Раймонда Хеттингера и Марка Дикинсона; bpo-3439).
Поля в строках
format()
теперь могут быть автоматически пронумерованы:>>> 'Sir {} of {}'.format('Gallahad', 'Camelot') 'Sir Gallahad of Camelot'
Раньше для строки требовались пронумерованные поля, например:
'Sir {0} of {1}'
.(Внесено Эриком Смитом; bpo-5237).
Функция
string.maketrans()
устарела и заменена новыми статическими методами,bytes.maketrans()
иbytearray.maketrans()
. Это изменение устраняет путаницу в том, какие типы поддерживались модулемstring
. Теперьstr
,bytes
иbytearray
имеют собственные методы maketrans и translate с промежуточными таблицами перевода соответствующего типа.(Внесено Георгом Брандлом; bpo-5675).
Синтаксис оператора
with
теперь позволяет использовать несколько менеджеров контекста в одном операторе:>>> with open('mylog.txt') as infile, open('a.out', 'w') as outfile: ... for line in infile: ... if '<critical>' in line: ... outfile.write(line)
В новом синтаксисе функция
contextlib.nested()
больше не нужна и теперь является устаревшей.(При участии Георга Брандла и Маттиаса Брандстрема; appspot issue 53094).
round(x, n)
теперь возвращает целое число, если x - целое число. Ранее он возвращал float:>>> round(1123, -2) 1100
(Предоставлено Марком Дикинсоном; bpo-4707).
Теперь Python использует алгоритм Дэвида Гея для поиска кратчайшего представления с плавающей точкой, которое не меняет своего значения. Это должно помочь уменьшить некоторую путаницу, связанную с двоичными числами с плавающей точкой.
Это легко понять на примере такого числа, как
1.1
, которое не имеет точного эквивалента в двоичной системе с плавающей запятой. Поскольку точного эквивалента нет, выражение типаfloat('1.1')
оценивается до ближайшего представимого значения, которым является0x1.199999999999ap+0
в шестнадцатеричной системе или1.100000000000000088817841970012523233890533447265625
в десятичной. Это ближайшее значение использовалось и продолжает использоваться в последующих вычислениях с плавающей запятой.Новым является способ отображения числа. Раньше в Python использовался простой подход. Значение
repr(1.1)
вычислялось какformat(1.1, '.17g')
, которое оценивалось в'1.1000000000000001'
. Преимущество использования 17 цифр заключалось в том, что оно опиралось на гарантии IEEE-754, гарантируя, чтоeval(repr(1.1))
будет округляться точно до своего исходного значения. Недостатком было то, что многие люди находили вывод запутанным (ошибочно принимая внутренние ограничения двоичного представления с плавающей точкой за проблему самого Python).Новый алгоритм для
repr(1.1)
более умный и возвращает'1.1'
. По сути, он перебирает все эквивалентные представления строк (те, которые хранятся с одним и тем же базовым значением float) и возвращает самое короткое представление.Новый алгоритм стремится выдать более чистые представления, когда это возможно, но он не меняет базовые значения. Таким образом,
1.1 + 2.2 != 3.3
все еще имеет место, даже если представления могут говорить об обратном.Новый алгоритм зависит от наличия определенных возможностей в базовой реализации вычислений с плавающей запятой. Если требуемые функции не найдены, будет продолжать использоваться старый алгоритм. Кроме того, протоколы text pickle обеспечивают кроссплатформенную переносимость, используя старый алгоритм.
(При участии Эрика Смита и Марка Дикинсона; bpo-1580)
Новые, улучшенные и устаревшие модули¶
Добавлен класс
collections.Counter
для поддержки удобного подсчета уникальных элементов в последовательности или итерируемой таблице:>>> Counter(['red', 'blue', 'red', 'green', 'blue', 'blue']) Counter({'blue': 3, 'red': 2, 'green': 1})
(Внесено Раймондом Хеттингером; bpo-1696199).
Добавлен новый модуль
tkinter.ttk
для доступа к набору тематических виджетов Tk. Основная идея ttk заключается в том, чтобы отделить, насколько это возможно, код, реализующий поведение виджета, от кода, реализующего его внешний вид.(Предоставлено Гильерме Поло; bpo-2983)
Классы
gzip.GzipFile
иbz2.BZ2File
теперь поддерживают протокол управления контекстом:>>> # Automatically close file after writing >>> with gzip.GzipFile(filename, "wb") as f: ... f.write(b"xxx")
(Предоставлено Антуаном Питру.)
Модуль
decimal
теперь поддерживает методы создания десятичного объекта из двоичногоfloat
. Преобразование является точным, но иногда может вызывать удивление:>>> Decimal.from_float(1.1) Decimal('1.100000000000000088817841970012523233890533447265625')
Длинный десятичный результат показывает фактическую двоичную дробь, хранящуюся для 1.1. Дробь имеет много цифр, потому что 1.1 не может быть точно представлена в двоичном виде.
(Предоставлено Раймондом Хеттингером и Марком Дикинсоном).
В модуле
itertools
появились две новые функции. Функцияitertools.combinations_with_replacement()
- одна из четырех для генерации комбинаторики, включая перестановки и декартовы произведения. Функцияitertools.compress()
имитирует своего тезку из APL. Кроме того, существующая функцияitertools.count()
теперь имеет необязательный аргумент шаг и может принимать любой тип счетной последовательности, включаяfractions.Fraction
иdecimal.Decimal
:>>> [p+q for p,q in combinations_with_replacement('LOVE', 2)] ['LL', 'LO', 'LV', 'LE', 'OO', 'OV', 'OE', 'VV', 'VE', 'EE'] >>> list(compress(data=range(10), selectors=[0,0,1,1,0,1,0,1,0,0])) [2, 3, 5, 7] >>> c = count(start=Fraction(1,2), step=Fraction(1,6)) >>> [next(c), next(c), next(c), next(c)] [Fraction(1, 2), Fraction(2, 3), Fraction(5, 6), Fraction(1, 1)]
(Предоставлено Раймондом Хеттингером.)
collections.namedtuple()
теперь поддерживает ключевой аргумент rename, который позволяет автоматически преобразовывать недействительные имена полей в позиционные имена в виде _0, _1 и т. д. Это полезно, когда имена полей создаются внешним источником, таким как CSV-заголовок, список полей SQL или пользовательский ввод:>>> query = input() SELECT region, dept, count(*) FROM main GROUPBY region, dept >>> cursor.execute(query) >>> query_fields = [desc[0] for desc in cursor.description] >>> UserQuery = namedtuple('UserQuery', query_fields, rename=True) >>> pprint.pprint([UserQuery(*row) for row in cursor]) [UserQuery(region='South', dept='Shipping', _2=185), UserQuery(region='North', dept='Accounting', _2=37), UserQuery(region='West', dept='Sales', _2=419)]
(Внесено Раймондом Хеттингером; bpo-1818).
Функции
re.sub()
,re.subn()
иre.split()
теперь принимают параметр flags.(Предоставлено Грегори Смитом.)
Модуль
logging
теперь реализует простой классlogging.NullHandler
для приложений, которые не используют логирование, но вызывают библиотечный код, который его использует. Установка обработчика с нулевым значением позволит избавиться от ложных предупреждений типа «Не удалось найти обработчиков для логгера foo»:>>> h = logging.NullHandler() >>> logging.getLogger("foo").addHandler(h)
(Предоставлено Vinay Sajip; bpo-4384).
Модуль
runpy
, поддерживающий переключатель командной строки-m
, теперь поддерживает выполнение пакетов, ища и выполняя подмодуль__main__
при указании имени пакета.(Предоставлено Andi Vajda; bpo-4195).
Модуль
pdb
теперь может получить доступ и отобразить исходный код, загруженный черезzipimport
(или любой другой соответствующий PEP 302 загрузчик).(Внесено Александром Белопольским; bpo-4201)
Объекты
functools.partial
теперь можно мариновать.
(Предложено Антуаном Питру и Джесси Ноллером. Реализовано Джеком Дидерихом; bpo-5228).
Добавьте темы справки
pydoc
для символов, чтобыhelp('@')
работал как положено в интерактивной среде.(Внесено Дэвидом Лабаном; bpo-4739).
Модуль
unittest
теперь поддерживает пропуск отдельных тестов или классов тестов. Также поддерживается пометка теста как ожидаемого провала - теста, о котором известно, что он сломан, но который не должен быть засчитан как провал в TestResult:class TestGizmo(unittest.TestCase): @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows") def test_gizmo_on_windows(self): ... @unittest.expectedFailure def test_gimzo_without_required_library(self): ...
Также были добавлены тесты на исключения для работы с менеджерами контекста, использующими оператор
with
:def test_division_by_zero(self): with self.assertRaises(ZeroDivisionError): x / 0
Кроме того, было добавлено несколько новых методов утверждения, включая
assertSetEqual()
,assertDictEqual()
,assertDictContainsSubset()
,assertListEqual()
,assertTupleEqual()
,assertSequenceEqual()
,assertRaisesRegexp()
,assertIsNone()
иassertIsNotNone()
.(Предоставлено Бенджамином Петерсоном и Антуаном Питру).
В модуле
io
появились три новые константы для методаseek()
:SEEK_SET
,SEEK_CUR
иSEEK_END
.Кортеж
sys.version_info
теперь является именованным кортежем:>>> sys.version_info sys.version_info(major=3, minor=1, micro=0, releaselevel='alpha', serial=2)
(Внесено Россом Лайтом; bpo-4285).
Модули
nntplib
иimaplib
теперь поддерживают IPv6.Модуль
pickle
был адаптирован для лучшей совместимости с Python 2.x при использовании с протоколом 2 или ниже. Реорганизация стандартной библиотеки изменила формальные ссылки для многих объектов. Например,__builtin__.set
в Python 2 называетсяbuiltins.set
в Python 3. Это изменение затруднило попытки обмена данными между разными версиями Python. Но теперь, когда выбран протокол 2 или ниже, pickler будет автоматически использовать старые имена Python 2 как для загрузки, так и для дампа. Эта перестановка включена по умолчанию, но может быть отключена с помощью опции fix_imports:>>> s = {1, 2, 3} >>> pickle.dumps(s, protocol=0) b'c__builtin__\nset\np0\n((lp1\nL1L\naL2L\naL3L\natp2\nRp3\n.' >>> pickle.dumps(s, protocol=0, fix_imports=False) b'cbuiltins\nset\np0\n((lp1\nL1L\naL2L\naL3L\natp2\nRp3\n.'
Досадным, но неизбежным побочным эффектом этого изменения является то, что пикули протокола 2, созданные в Python 3.1, не будут читаться в Python 3.0. При переносе данных между реализациями Python 3.x следует использовать новейший протокол pickle, протокол 3, поскольку он не пытается сохранить совместимость с Python 2.x.
(Предоставлено Александром Вассалотти и Антуаном Питру, bpo-6137).
Добавлен новый модуль
importlib
. Он предоставляет полную, переносимую, чисто питоновскую эталонную реализацию оператораimport
и его аналога, функции__import__()
. Это существенный шаг вперед в документировании и определении действий, происходящих при импорте.(Предоставлено Бреттом Кэнноном.)
Оптимизации¶
Добавлены значительные улучшения производительности:
Новая библиотека ввода-вывода (как определено в PEP 3116) была написана в основном на Python и быстро оказалась проблемным узким местом в Python 3.0. В Python 3.1 библиотека ввода-вывода была полностью переписана на C и работает в 2-20 раз быстрее в зависимости от поставленной задачи. Чистая версия Python по-прежнему доступна для экспериментов с помощью модуля
_pyio
.(Предоставлено Амори Форжо д’Арк и Антуаном Питру).
Добавлена эвристика, благодаря которой кортежи и массивы, содержащие только не отслеживаемые объекты, не отслеживаются сборщиком мусора. Это может уменьшить размер коллекций и, следовательно, накладные расходы на сборку мусора в длительно работающих программах, в зависимости от особенностей использования ими типов данных.
(Предоставлено Антуаном Питру, bpo-4688).
При включении опции configure
--with-computed-gotos
в компиляторах, которые ее поддерживают (в частности, gcc, SunPro, icc), цикл оценки байткода компилируется с новым механизмом диспетчеризации, который дает ускорение до 20 %, в зависимости от системы, компилятора и бенчмарка.(Внесено Антуаном Питру вместе с рядом других участников, bpo-4753).
Декодирование UTF-8, UTF-16 и LATIN-1 теперь происходит в два-четыре раза быстрее.
(Предоставлено Антуаном Питру и Амори Форжо д’Арк, bpo-4868).
Модуль
json
теперь имеет расширение на языке C, что значительно повышает его производительность. Кроме того, API был изменен таким образом, что json работает только сstr
, а не сbytes
. Это изменение делает модуль близким к JSON specification, который определяется в терминах Unicode.(Внесено Бобом Ипполито и переведено на Py3.1 Антуаном Питру и Бенджамином Петерсоном; bpo-4136).
При распаковке теперь сохраняются имена атрибутов распакованных объектов. Это экономит память и позволяет уменьшать размер маринованных объектов.
(При участии Джейка Макгуайра и Антуана Питру; bpo-5084).
IDLE¶
В меню формата IDLE теперь есть опция удаления пробельных символов из исходного файла.
(Предоставлено Роджером Д. Серви; bpo-5150).
Изменения в сборке и C API¶
Изменения в процессе сборки Python и в C API включают:
Целочисленные числа теперь хранятся внутри либо в базе
2**15
, либо в базе2**30
, причем база определяется во время сборки. Ранее они всегда хранились в base2**15
. Использование базы2**30
дает значительный прирост производительности на 64-битных машинах, но результаты бенчмарков на 32-битных машинах были неоднозначными. Поэтому по умолчанию используется база2**30
на 64-битных машинах и база2**15
на 32-битных; на Unix есть новая опция configure--enable-big-digits
, которая может быть использована для отмены этого значения.Помимо повышения производительности, это изменение должно быть незаметно для конечных пользователей, за одним исключением: для целей тестирования и отладки есть новый
sys.int_info
, который предоставляет информацию о внутреннем формате, указывая количество бит на цифру и размер в байтах типа C, используемого для хранения каждой цифры:>>> import sys >>> sys.int_info sys.int_info(bits_per_digit=30, sizeof_digit=4)
(Предоставлено Марком Дикинсоном; bpo-4258).
Функция
PyLong_AsUnsignedLongLong()
теперь обрабатывает отрицательные pylong, поднимаяOverflowError
вместоTypeError
.(При участии Марка Дикинсона и Лисандро Далькрина; bpo-5175).
Утратил силу
PyNumber_Int()
. Вместо этого используйтеPyNumber_Long()
.(Предоставлено Марком Дикинсоном; bpo-4910).
Добавлена новая функция
PyOS_string_to_double()
для замены устаревших функцийPyOS_ascii_strtod()
иPyOS_ascii_atof()
.(Предоставлено Марком Дикинсоном; bpo-5914).
Добавлен
PyCapsule
в качестве заменыPyCObject
. API. Основное отличие заключается в том, что новый тип имеет хорошо определенный интерфейс для передачи информации о безопасности типизации и менее сложную сигнатуру для вызова деструктора. Старый тип имел проблемный API и теперь устарел.(Предоставлено Ларри Гастингсом; bpo-5630).
Переход на Python 3.1¶
В этом разделе перечислены ранее описанные изменения и другие исправления, которые могут потребовать внесения изменений в ваш код:
Новые представления строк с плавающей точкой могут нарушить существующие док-тесты. Например:
def e(): '''Compute the base of natural logarithms. >>> e() 2.7182818284590451 ''' return sum(1/math.factorial(x) for x in reversed(range(30))) doctest.testmod() ********************************************************************** Failed example: e() Expected: 2.7182818284590451 Got: 2.718281828459045 **********************************************************************
Автоматическая перестановка имен в модуле pickle для протокола 2 или ниже может сделать пикули Python 3.1 нечитаемыми в Python 3.0. Одно из решений - использовать протокол 3. Другое решение - установить опцию fix_imports в
False
. Подробнее см. обсуждение выше.