Что нового в Python 3,3?

В данной статье описываются новые функции в Python 3.3, по сравнению с 3.2. Python 3.3 был выпущен 29 сентября 2012 года.

Основная информация

Новые возможности синтаксиса:

  • Новое выражение yield from для реализации генераторов.
  • Синтаксис u"unicode" снова разрешен для объектов типа str.

Новые встроенные модули:

  • faulthandler (отладка низкоуровневых ошибок)
  • ipaddress (высокоуровневая работа с IP-адресами и масками)
  • lzma (компрессия с использованием алгоритма XZ / LZMA)
  • venv (виртуальная среда Python)

Новые встроенные улучшения:

  • Переработана иерархия I/O исключений

Реализация улучшений:

  • Переписана машина импорта на основе importlib
  • Более компактные строки unicode
  • Более компактные словари

Улучшения безопасности:

  • Рандомизация хеш-суммы включена по умолчанию

PEP 405: Виртуальная среда

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

Этот PEP добавляет модуль venv для программного доступа, и скрипт pyvenv для доступа к командной строке и администрирования. Интерпретатору Python становится известно о pvenv.cfg файле, существование которого сигнализирует базу деревьев каталогов виртуальной среды.

PEP 420: Пространство имен пакетов

Встроенная поддержка пакетов, которые не требуют файлы __init__.py

PEP 393: гибкое представление строк

Строки изменены для поддержки нескольких внутренних представлений, в зависимости от символа с наибольшим порядковым Unicode (1, 2 или 4 байта). Это позволяет эффективно представлять строки в большинстве случаев, но дает доступ к полному UCS-4 на всех системах. Для совместимости с существующим API, несколько представлений могут существовать параллельно, с течением времени, эта совместимость должна быть прекращена.

На стороне C API, PEP 393 является полностью обратно совместимым. API должны оставаться доступными по крайней мере пять лет. Приложения, использующие API не будут в полной мере пользоваться сокращением памяти, или - еще хуже - может использовать немного больше памяти, так как Python, возможно, придется поддерживать две версии каждой строки (в устаревшем формате и в новом эффективного хранении).

Функциональность

Изменения, внесенные PEP 393:

  • Python теперь всегда поддерживает полный набор кодов Unicode, в том числе не-BMP символы (т.е. от U+0000 до U+10FFFF). Различие между узкой и широкой строкой больше не существует, и Python теперь ведет себя как при широкой сборке, даже под Windows.
  • Со смертью узкой версии, проблемы, характерные для узкой версии также были исправлены, например:
    • len() теперь всегда возвращает 1 для не-BMP символов, поэтому len('\U0010FFFF') == 1 ;
    • суррогатные пары не рекомбинируют в строковые литералы, так '\uDBFF\uDFFF' != '\U0010FFFF' ;
    • индекс или срез не-BMP символов возвращает ожидаемое значение, поэтому '\U0010FFFF'[0] теперь возвращает '\U0010FFFF' , а не '\uDBFF' ;
    • Все другие функции в стандартной библиотеке теперь корректно обрабатывают не-BMP коды.
  • Значение sys.maxunicode теперь всегда 1114111 ( 0x10FFFF в шестнадцатеричной). PyUnicode_GetMax() по-прежнему возвращает либо 0xFFFF или 0x10FFFF для обратной совместимости, и его не следует использовать с новым API Unicode.
  • ./configure флаг --with-wide-unicode был удален.

Производительность и использование ресурсов

Хранение Unicode строк теперь зависит от максимального кода в ​​кодовой строке:

  • ASCII и Latin1 строки ( U +0000- U +00 FF ) используют 1 байт;
  • BMP строки ( U +0000- U + FFFF ) используют 2 байта;
  • не-BMP строки ( U +10000- U +10 FFFF ) используют 4 байта.

Результатом является то, что для большинства приложений, использование памяти должно значительно уменьшиться - особенно по сравнению с бывшим Unicode, так как во многих случаях, строки будут чистым ASCII даже в международном контексте (потому что много строк хранят данные не-человеческим языком, такие как XML-фрагменты, HTTP заголовки, JSON-кодированные данных и т.д.). Мы также надеемся, что она, по тем же причинам, повысит эффективность кэш-памяти процессора для нетривиальных приложений. Использование памяти Python 3.3 в два-три раза меньше, чем Python 3.2, и немного меньше, чем Python 2.7, на тесте Django.

PEP 3151: Переработка ОС и IO иерархии исключений

Иерархия исключений упрощена и более детальна.

Вам не придется больше беспокоиться о выборе подходящего типа исключения между OSError, IOError, EnvironmentError, WindowsError, mmap.error, socket.error или select.error. Все эти типы исключений теперь только один: OSError. Другие имена хранятся в качестве псевдонимов для обеспечения совместимости.

Кроме того, теперь легче поймать определенное условие ошибки. Вместо проверки атрибут ERRNO для конкретной постоянной из ERRNO модуля, вы можете обрабатывать конкретный подкласс OSError. Доступные подклассы:

  • BlockingIOError
  • ChildProcessError
  • ConnectionError
  • FileExistsError
  • FileNotFoundError
  • InterruptedError
  • IsADirectoryError
  • NotADirectoryError
  • PermissionError
  • ProcessLookupError
  • TimeoutError

И ConnectionError также имеет подклассы:

  • BrokenPipeError
  • ConnectionAbortedError
  • ConnectionRefusedError
  • ConnectionResetError

Например, следующий код, написанный для Python 3.2:

from errno import ENOENT, EACCES, EPERM

try:
    with open("document.txt") as f:
        content = f.read()
except IOError as err:
    if err.errno == ENOENT:
        print("document.txt file is missing")
    elif err.errno in (EACCES, EPERM):
        print("You are not allowed to read document.txt")
    else:
        raise

Теперь может быть написан без импорта ERRNO и без ручной проверки атрибутов исключения:

try:
    with open("document.txt") as f:
        content = f.read()
except FileNotFoundError:
    print("document.txt file is missing")
except PermissionError:
    print("You are not allowed to read document.txt")

PEP 380: Синтаксис для делегирования Subgenerator

PEP 380 добавляет выражение yield from, что позволяет генератору делегировать часть своих операций на другой генератор. Это позволяет части кода, содержащего 'yield', чтобы быть вынесена и помещена в другой генератор. Кроме того, subgenerator разрешили вернуться со значением, а значение становится доступным для делегирования генератора.

Хотя предназначен в первую очередь для использования в делегировании subgenerator, yield from фактически позволяет делегировать произвольные subiterators.

Для простых итераторов yield from iterable это просто сокращенная форма для for item in iterable: yield item

>>> def g(x):
...     yield from range(x, 0, -1)
...     yield from range(x)
...
>>> list(g(5))
[5, 4, 3, 2, 1, 0, 1, 2, 3, 4]

Однако, в отличие от обычного цикла, yield from позволяет и вернуть окончательное значение во внешний генератор:

>>> def accumulate(start=0):
...     tally = start
...     while 1:
...         next = yield
...         if next is None:
...             return tally
...         tally += next
...
>>> def gather_tallies(tallies, start=0):
...     while 1:
...         tally = yield from accumulate()
...         tallies.append(tally)
...
>>> tallies = []
>>> acc = gather_tallies(tallies)
>>> next(acc) # Ensure the accumulator is ready to accept values
>>> for i in range(10):
...     acc.send(i)
...
>>> acc.send(None) # Finish the first tally
>>> for i in range(5):
...     acc.send(i)
...
>>> acc.send(None) # Finish the second tally
>>> tallies
[45, 10]

Основной принцип изменения - позволить разделить генератор на несколько субгенераторов так же легко, как одна большая функция может быть разбита на несколько подфункций.

PEP 409: Подавление контекста исключения

PEP 409 вводит новый синтаксис, который позволяет отключить контекст исключений. Это позволяет получать чистое сообщение об ошибках в приложениях, конвертировать в разные типы исключений:

>>> class D:
...     def __init__(self, extra):
...         self._extra_attributes = extra
...     def __getattr__(self, attr):
...         try:
...             return self._extra_attributes[attr]
...         except KeyError:
...             raise AttributeError(attr) from None
...
>>> D({}).x
Traceback (most recent call last):
  File "", line 1, in
  File "", line 8, in __getattr__
AttributeError: x

Без выражения from None будет возбуждено стандартное исключение:

>>> class C:
...     def __init__(self, extra):
...         self._extra_attributes = extra
...     def __getattr__(self, attr):
...         try:
...             return self._extra_attributes[attr]
...         except KeyError:
...             raise AttributeError(attr)
...
>>> C({}).x
Traceback (most recent call last):
  File "", line 6, in __getattr__
KeyError: 'x'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "", line 1, in
  File "", line 8, in __getattr__
AttributeError: x

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

>>> try:
...     D({}).x
... except AttributeError as exc:
...     print(repr(exc.__context__))
...
KeyError('x',)

Полные имена для классов и функций

Функции и объекты класса в python 3.3 имеют новый атрибут __qualname__ (представляет «путь» от модуля верхнего уровня). Для глобальных функций и классов это то же, что и __name__ . Для других функций и классов, он обеспечивает лучшую информацию о том, где они были фактически определены, и как они могут быть доступны из глобальной области.

Пример с (несвязанным) методом:

>>> class C:
...     def meth(self):
...         pass
>>> C.meth.__name__
'meth'
>>> C.meth.__qualname__
'C.meth'

Пример с вложенными классами:

>>> class C:
...     class D:
...         def meth(self):
...             pass
...
>>> C.D.__name__
'D'
>>> C.D.__qualname__
'C.D'
>>> C.D.meth.__name__
'meth'
>>> C.D.meth.__qualname__
'C.D.meth'

Пример с вложенной функцией:

>>> def outer():
...     def inner():
...         pass
...     return inner
...
>>> outer().__name__
'inner'
>>> outer().__qualname__
'outer.<locals>.inner'

Строковое представление этих объектов также изменено, для отображения большей информации:

>>> str(C.D)
"<class '__main__.C.D'>"
>>> str(C.D.meth)
'<function C.D.meth at 0x7f6376f5f730>'

PEP 412: Ключ-шеринг словари

Словари в python 3.3 теперь имеют возможность совместно использовать часть памяти, хранящую ключи и их хеши, что повышает производительность большинства не встроенных типов.

Обсуждение вопросов, не связанных со статьёй (в т.ч. комментарии типа "Помогите!"), ведётся на форуме pythonworld.club, а не в комментариях.

Для вставки кода на Python в комментарий заключайте его в теги <pre><code class="python3">Ваш код</code></pre>
Опечатка в тексте:
Послать сообщение об ошибке автору?