Раздел: Статьи / Питон /

Что нового в Python 3.1

Все способы изучить Python Все способы изучить Python

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

В Python 3.1 по сравнению с версией 3.0 добавлено довольно много изменений. А именно…

Упорядоченные словари

Обычные словари Python перебирают пары ключ/значение в произвольном порядке. На протяжении многих лет ряд авторов писали альтернативные реализации, которые запоминают порядок первоначальной вставки ключей. Основываясь на опыте этих внедрений, введен новый класс collections.OrderedDict.

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

Стандартная библиотека теперь поддерживает использование упорядоченных словарей в нескольких модулях. Модуль configparser использует их по умолчанию. Это позволяет считывать, изменять и затем записывать обратно файлы конфигурации в их первоначальном порядке. Метод _asdict() для collections.namedtuple() теперь возвращает упорядоченный словарь со значениями, отображаемыми в том же порядке, что и базовые индексы кортежей. Модуль json создается с помощью object_pairs_hook, чтобы декодер мог создавать упорядоченные значения. Также была добавлена поддержка сторонних инструментов, таких как PyYAML.

Спецификатор формата для разделения тысяч

Встроенная функция 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.

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

Некоторые небольшие изменения, внесенные в основу языка Python, заключаются в следующем:

Каталоги и zip-архивы, содержащие файл __main__.py теперь можно выполнить напрямую, передав его имя интерпретатору. Каталог или zip-файл автоматически вставляется в качестве первой записи в sys.path.

Тип 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

Поля в строках format() теперь можно автоматически нумеровать (раньше для строки требовались бы пронумерованные поля, такие как 'Sir {0} of {1}'):

>>> 'Sir {} of {}'.format('Gallahad', 'Camelot')
'Sir Gallahad of Camelot'

Функция string.maketrans() устарела и заменена новыми статическими методами bytes.maketrans() и bytearray.maketrans(). Это изменение устраняет путаницу, связанную с тем, какие типы поддерживались модулем string. Теперь str, bytes и bytearray имеют свои собственные методы maketrans и translate с промежуточными таблицами перевода соответствующего типа.

Синтаксис оператора with теперь позволяет использовать несколько контекстных менеджеров в одном операторе (с новым синтаксисом функция contextlib.nested() больше не нужна и теперь устарела):

>>> with open('mylog.txt') as infile, open('a.out', 'w') as outfile:
...   for line in infile:
...     if '' in line:
...       outfile.write(line)

round(x, n) теперь возвращает целое число, если x является целым числом. Ранее он возвращал значение с плавающей запятой:

>>> round(1123, -2)
1100

Python теперь использует алгоритм Дэвида Гэя для нахождения кратчайшего представления с плавающей запятой, которое не изменяет своего значения. Это должно помочь смягчить некоторую путаницу, связанную с двоичными числами с плавающей запятой. Значение легко увидеть с помощью такого числа, как 1.1, которое не имеет точного эквивалента в двоичном формате с плавающей запятой.

Поскольку точного эквивалента не существует, выражение типа float('1.1') вычисляется до ближайшего представимого значения, которое равно 0x1.199999999999ap+0 в шестнадцатеричном формате или 1.1000000000000088817841970012523233890533447265625 в десятичном формате. Это ближайшее значение использовалось и до сих пор используется в последующих вычислениях с плавающей запятой. Что нового, так это то, как отображается номер.

Раньше Python использовал простой подход. Значение repr(1.1) вычислялось как format(1.1, '.17g'), который оценивался как '1.10000000000001'. Преимущество использования 17 цифр заключалось в том, что оно основывалось на правилах IEEE-754, гарантирующих, что eval(repr(1.1)) будет возвращаться точно к своему исходному значению. Недостатком является то, что многие люди сочли вывод сбивающим с толку (ошибочно приняв внутренние ограничения двоичного представления с плавающей запятой за проблему с самим Python).

Новый алгоритм для repr(1.1) более умный и возвращает '1.1'. По сути, он выполняет поиск по всем эквивалентным строковым представлениям (тем, которые сохраняются с тем же базовым значением с плавающей запятой) и возвращает кратчайшее представление. Новый алгоритм, как правило, выдает более чистые представления, когда это возможно, но он не изменяет базовые значения.

Таким образом, по-прежнему имеет место тот факт, что 1.1 + 2.2 != 3.3, хотя представления могут предполагать обратное. Новый алгоритм зависит от определенных функций базовой реализации с плавающей запятой. Если требуемые функции не будут найдены, старый алгоритм будет продолжать использоваться. Кроме того, протоколы текстовых преобразований обеспечивают кроссплатформенную переносимость с использованием старого алгоритма.

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

Добавлен класс collections.Counter для поддержки удобного подсчета уникальных элементов в последовательности или повторяющихся:

>>> Counter(['red', 'blue', 'red', 'green', 'blue', 'blue'])
Counter({'blue': 3, 'red': 2, 'green': 1})

Добавлен новый модуль tkinter.ttk для доступа к набору виджетов на тему Tk. Основная идея ttk состоит в том, чтобы отделить, насколько это возможно, код, реализующий поведение виджета, от кода, реализующего его внешний вид.

Классы gzip.GzipFile и bz2.BZ2File теперь поддерживают протокол управления контекстом:

>>> # Automatically close file after writing
>>> with gzip.GzipFile(filename, "wb") as f:
...     f.write(b"xxx")

Модуль decimal теперь поддерживает методы создания десятичного объекта из двоичного числа с плавающей запятой. Преобразование является точным, но иногда может быть неожиданным:

>>> Decimal.from_float(1.1)
Decimal('1.100000000000000088817841970012523233890533447265625')

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

Модуль itertools расширился двумя новыми функциями. Функция itertools.combinations_with_replacement() является одной из четырех для генерации комбинаторики, включая перестановки и декартовы произведения. Функция itertools.compress() имитирует одноимённую функцию из APL. Кроме того, существующая функция itertools.count() теперь имеет необязательный аргумент step и может принимать любой тип числовой последовательности, включая 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)]

Функции re.sub(), re.subn() и re.split() теперь принимают параметр flags.

Модуль logging теперь реализует простой класс logging.NullHandler для приложений, которые не используют ведение журнала, но вызывают библиотечный код, который это делает. Передача в обработчик значения null будет подавлять ложные предупреждения, такие как “Не удалось найти обработчики для logger foo”:

>>> h = logging.NullHandler()
>>> logging.getLogger("foo").addHandler(h)

Модуль runpy, который поддерживает переключатель командной строки -m, теперь поддерживает выполнение пакетов путем поиска и выполнения подмодуля __main__ при указании имени пакета.

Модуль pdb теперь может получать доступ и отображать исходный код, загруженный через zipimport (или любой другой соответствующий PEP 302 загрузчик).

Объекты functools.partial теперь можно сериализовать.

Добавлены pydoc разделов справки для символов, чтобы help('@') работала должным образом в интерактивной среде.

Модуль 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)

Модули nntplib и imaplib теперь поддерживают IPv6.

Модуль pickle был адаптирован для лучшей совместимости с Python 2.x при использовании с протоколом 2 или ниже. Реорганизация стандартной библиотеки изменила формальную ссылку для многих объектов. Например, __builtin__.set в Python 2 называется buildings.set на Python 3. Это изменение поставило в тупик усилия по обмену данными между различными версиями Python. Но теперь, когда выбран протокол 2 или ниже, средство выбора автоматически будет использовать старые имена 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.'

Прискорбным, но неизбежным побочным эффектом этого изменения является то, что протоколы pickle 2, созданные Python 3.1, не будут доступны для чтения с помощью Python 3.0. Последний протокол pickle, протокол 3, следует использовать при переносе данных между реализациями Python 3.x, поскольку он не пытается оставаться совместимым с Python 2.x.

Был добавлен новый модуль importlib. Он предоставляет полную, переносимую, чистую эталонную реализацию инструкции import на языке Python и ее аналога, функции __import__(). Это представляет собой существенный шаг вперед в документировании и определении действий, которые происходят во время импорта.

Оптимизации

Были добавлены значительные улучшения производительности:

  • Новая библиотека ввода-вывода (как определено в PEP 3116) была в основном написана на Python и быстро оказалась проблемным узким местом в Python 3.0. В Python 3.1 библиотека ввода-вывода была полностью переписана на C и работает от 2 до 20 раз быстрее в зависимости от поставленной задачи. Чистая версия Python по-прежнему доступна для экспериментов с помощью модуля _pyio.
  • Добавлена эвристика, позволяющая сборщику мусора не отслеживать кортежи и словари, содержащие только неотслеживаемые объекты. Это может уменьшить размер коллекций и, следовательно, расходы ресурсов на сборку мусора в длительно работающих программах, в зависимости от их конкретного использования типов данных.
  • Включение опции настройки с именем --with-computed-gotos в компиляторах, которые её поддерживают (в частности: gcc, SunPro, icc), цикл оценки байт-кода компилируется с помощью нового механизма диспетчеризации, который обеспечивает ускорение до 20%, в зависимости от системы, компилятора и эталона.
  • Декодирование UTF-8, UTF-16 и LATIN-1 теперь в два-четыре раза быстрее.
  • Модуль json теперь имеет расширение C для существенного повышения его производительности. Кроме того, API был изменен таким образом, чтобы json работал только с str, а не с bytes. Это изменение приводит к тому, что модуль полностью соответствует спецификации JSON, которая определена в терминах Unicode.
  • При удалении имена атрибутов выделенных объектов теперь интернируются. Это экономит память и позволяет сериализации быть меньше.

IDLE

Меню форматирования IDLE теперь предоставляет возможность удалять конечные пробелы из исходного файла.

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

Изменения в процессе сборки Python и в C API включают следующее…

Целые числа теперь хранятся внутри либо в базе 2**15, либо в базе 2**30, причем база определяется во время сборки. Раньше они всегда хранились в базе 2**15. Использование базы 2**30 обеспечивает значительное повышение производительности на 64-разрядных машинах, но результаты тестов на 32-разрядных машинах были неоднозначными. Следовательно, по умолчанию используется база 2**30 на 64-разрядных машинах и база 2**15 на 32-разрядных машинах. В Unix есть новая опция настройки -enable-big-digits, которая может использоваться для переопределения этого значения по умолчанию.

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

>>> import sys
>>> sys.int_info
sys.int_info(bits_per_digit=30, sizeof_digit=4)

Функция PyLong_AsUnsignedLongLong() теперь обрабатывает отрицательный pylong, вызывая OverflowError вместо TypeError.

Устарела функция PyNumber_Int(). Вместо неё используйте PyNumber_Long().

Добавлена новая функция PyOS_string_to_double() для замены устаревших функций pyos_ascii_strtod() и pyos_ascii_atof().

Добавлен PyCapsule в качестве замены API PyCObject. Принципиальное отличие заключается в том, что новый тип имеет четко определенный интерфейс для передачи информации о безопасности ввода и менее сложную сигнатуру для вызова деструктора. У старого типа был проблемный API, и теперь он устарел.

Перенос на Python 3.1

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

Новые представления строк с плавающей запятой могут нарушать существующие doctests. Например:

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 или ниже может сделать pickles Python 3.1 нечитаемыми в Python 3.0. Одним из решений является использование протокола 3. Другое решение - установить для параметра fix_imports значение False. Более подробную информацию смотрите в обсуждении выше.


Учимся программировать на Python Учимся программировать на Python

Python - один из самых востребованных языков программирования. Подпишитесь на бесплатную рассылку и получайте статьи и видео о программировании на Python. Подробнее...

Инфо-МАСТЕР ®
Все права защищены ©
e-mail: mail@info-master.su

Яндекс.Метрика