Содержание страницы
Перенос кода с Python 2 на Python 3¶Porting Python 2 Code to Python 3
| автор: | Brett Cannon |
|---|
Аннотация
Поскольку Python 3 – будущее Python, а Python 2 всё ещё активно используется, полезно иметь свой проект доступным для обеих основных версий Python. Это руководство призвано помочь выбрать наиболее подходящую стратегию поддержки Python 2 и 3 для вашего проекта, а также объяснить, как её реализовать.
Если требуется портировать модуль расширения, а не чистый код Python, см. Портирование модулей расширения на Python 3.
Выбор стратегии¶Choosing a Strategy
Когда проект принимает решение о необходимости поддержки обеих версий Python 2 и 3, нужно определиться, как этого добиться. Выбранная стратегия будет зависеть от размера существующей кодовой базы проекта и от желаемой степени расхождения между кодовыми базами Python 2 и Python 3 (например, начав новую версию с Python 3).
Если ваш проект новый или кодовая база невелика, возможно, стоит рассмотреть написание/перенос всего кода для Python 3 и использование 3to2 для переноса кода на Python 2.
Если вы предпочитаете поддерживать кодовую базу, семантически и синтаксически совместимую с Python 2 и 3 одновременно, вы можете писать исходный код, совместимый с Python 2/3. Хотя это обычно приводит к несколько неидиоматичному коду, это означает, что вы сохраняете быстрый процесс разработки для себя как разработчика.
Наконец, у вас есть возможность использовать 2to3 для перевода кода Python 2 в код Python 3 (с некоторой ручной помощью). Это может быть реализовано в виде ветвления кода и использования 2to3 для создания ветки Python 3. Вы также можете позволить пользователям выполнять перевод автоматически во время установки, чтобы вам нужно было поддерживать только кодовую базу Python 2.
Независимо от выбранного подхода, перенос не так сложен и не требует столько времени, как может показаться изначально. Вы также можете решать задачу поэтапно, поскольку значительная часть переноса – это просто обновление кода в соответствии с текущими лучшими практиками совместимости с Python 2/3.
Универсальные советы¶Universal Bits of Advice
Независимо от выбранной стратегии, есть несколько моментов, которые стоит учесть.
Во-первых, убедитесь, что у вас надёжный набор тестов. Нужно быть уверенным, что всё продолжает работать, как и при поддержке новой минорной версии Python. Это означает, что ваш набор тестов должен быть тщательным и правильно перенесён между Python 2 и 3. Также, скорее всего, вы захотите использовать что-то вроде tox для автоматизации тестирования между виртуальными машинами Python 2 и Python 3.
Во-вторых, когда ваш проект получит поддержку Python 3, не забудьте добавить правильный классификатор на Cheeseshop (PyPI). Чтобы ваш проект был указан как совместимый с Python 3, он должен иметь классификатор Python 3 (из http://techspot.zzzeek.org/2011/01/24/zzzeek-s-guide-to-python-3-porting/):
setup(
name='Your Library',
version='1.0',
classifiers=[
# убедитесь, что используете :: Python *and* :: Python :: 3, чтобы
# pypi мог отобразить пакет на странице python 3
'Programming Language :: Python',
'Programming Language :: Python :: 3'
],
packages=['yourlibrary'],
# убедитесь, что добавили custom_fixers в MANIFEST.in
include_package_data=True,
# ...
)
Это приведёт к тому, что ваш проект появится в списке пакетов Python 3. Вы поймёте, что классификатор установлен правильно, так как при посещении страницы вашего проекта на Cheeseshop в левом верхнем углу страницы будет отображаться логотип Python 3.
В-третьих, проект six предоставляет библиотеку, которая помогает сгладить различия между Python 2 и 3. Если вы обнаружите, что есть сложный момент, который постоянно вызывает затруднения при переносе или сопровождении кода, рассмотрите возможность использования решения, совместимого на уровне исходного кода, основанного на six. Если вам нужно создать собственное совместимое с Python 2/3 решение, вы можете использовать sys.version_info[0] >= 3 в качестве защиты.
В-четвёртых, прочитайте обо всех подходах. То, что какой-то совет больше подходит для одного подхода, не означает, что он не применим к другим стратегиям.
В-пятых, откажитесь от поддержки старых версий Python, если возможно. Python 2.5 ввёл много полезного синтаксиса и библиотек, которые стали идиоматическими в Python 3. Python 2.6 ввёл future-операторы, которые значительно упрощают совместимость при переходе с Python 2 на 3. Python 2.7 продолжает эту тенденцию в стандартной библиотеке. Поэтому выберите самую новую версию Python, которую вы можете сделать минимально поддерживаемой, и работайте от неё.
Python 3 и 3to2¶Python 3 and 3to2
Если вы начинаете новый проект или ваша кодовая база достаточно мала, возможно, стоит рассмотреть написание кода для Python 3 и обратный перенос на Python 2 с помощью 3to2. Благодаря тому, что Python 3 более строг в некоторых вещах, чем Python 2 (например, байты и строки), трансляция исходного кода может быть проще и прямолинейнее, чем с Python 2 на 3. Кроме того, это даёт вам более непосредственный опыт разработки на Python 3, что, поскольку это будущее Python, хорошо в долгосрочной перспективе.
Недостаток этого подхода в том, что 3to2 – сторонний проект. Это означает, что основные разработчики Python (а значит, и данное руководство) не могут давать никаких гарантий относительно того, насколько хорошо 3to2 работает в любой момент времени. Однако нет оснований полагать, что 3to2 – некачественный проект.
Python 2 и 2to3¶Python 2 and 2to3
Включённый в состав Python начиная с версии 2.6, инструмент 2to3 (и модуль lib2to3) помогает переносить код с Python 2 на Python 3, выполняя различные трансформации исходного кода. Это идеальное решение для проектов, которые хотят ответвить код Python 3 от своей кодовой базы Python 2 и поддерживать их как независимые кодовые базы. Вы можете даже начать подготовку к использованию этого подхода уже сегодня, написав совместимый с будущими версиями код Python, который чисто работает в Python 2 вместе с 2to3; все описанные ниже шаги будут работать с кодом Python 2 до того момента, когда фактически начнётся использование 2to3.
Использование 2to3 в качестве этапа перевода по требованию во время установки также возможно, что избавляет от необходимости поддерживать отдельную кодовую базу Python 3, но у этого подхода есть недостатки. Хотя пользователям придётся заплатить за перевод только один раз при установке, вам как разработчику придётся нести эти затраты регулярно во время разработки. Если ваша кодовая база достаточно велика, этап перевода превращается в аналог компиляции, лишая вас быстрого процесса разработки, к которому вы привыкли в Python. Очевидно, время, необходимое для перевода проекта, варьируется, поэтому выполните пробный перевод, чтобы оценить, сколько времени это занимает, и решить, предпочитаете ли вы этот подход по сравнению с использованием исходного кода, совместимого с Python 2/3 или простым поддержанием отдельной кодовой базы Python 3.
Ниже приведены типичные шаги, которые предпринимает проект, использующий подход на основе 2to3 для поддержки Python 2 и 3.
Поддержка Python 2.7¶Support Python 2.7
Первым делом убедитесь, что ваш проект совместим с Python 2.7. Это хорошая практика, поскольку Python 2.7 – последний выпуск Python 2 и поэтому будет использоваться довольно долгое время. Это также позволяет использовать флаг -3 для Python, чтобы помочь обнаружить места в вашем коде, которые 2to3 не может обработать, но которые, как известно, вызывают проблемы.
Старайтесь поддерживать только Python 2.6 и новее¶Try to Support Python 2.6 and Newer Only
Хотя это возможно не для всех проектов, если вы можете поддерживать Python 2.6 и только более новые версии, ваша жизнь станет намного проще. Различные future-операторы, дополнения стандартной библиотеки и т.д. существуют только в Python 2.6 и новее, что очень помогает при переносе на Python 3. Но если ваш проект должен поддерживать Python 2.5 (или даже Python 2.4), то перенос на Python 3 всё ещё возможен.
Ниже перечислены преимущества, которые вы получаете, если вам нужно поддерживать только Python 2.6 и новее. Некоторые из этих вариантов являются личным выбором, в то время как другие настоятельно рекомендуются (те, что больше относятся к личному выбору, помечены как таковые). Если вы продолжаете поддерживать более старые версии Python, то вам, по крайней мере, нужно следить за ситуациями, которые эти решения исправляют.
from __future__ import print_function¶
Это личный выбор. 2to3 довольно хорошо обрабатывает перевод оператора print в функцию print, так что это необязательный шаг. Однако этот future-оператор помогает привыкнуть к набору print('Hello, World') вместо print 'Hello, World'.
from __future__ import unicode_literals¶
Ещё один личный выбор. Вы всегда можете пометить то, что должно быть (юникодной) строкой, префиксом u для достижения того же эффекта. Но независимо от того, используете вы этот future-оператор или нет, вы должны точно знать, какие строки Python 2 вы хотите сделать байтами, а какие – строками. Это означает, что вы должны как минимум пометить все строки, предназначенные для текста, префиксом u, если вы не используете этот future-оператор.
Байтовые литералы¶Bytes literals
Это очень важный момент. Возможность помечать строки Python 2, которые должны содержать байты, префиксом b помогает чётко разграничить, что является строкой Python 3, а что – нет. Когда запускается 2to3 на коде, все строки Python 2 становятся строками Python 3, если только они не помечены префиксом b.
Существуют некоторые различия между байтовыми литералами в Python 2 и Python 3, поскольку в Python 2 тип bytes является просто псевдонимом для str. Вероятно, самая большая «ловушка» – это то, что индексация возвращает разные значения. В Python 2 значением b'py'[1] является 'y', а в Python 3 – 121. Избежать этого расхождения можно, всегда выполняя срез размером в один элемент: b'py'[1:2] даёт 'y' в Python 2 и b'y' в Python 3 (то есть, достаточно близко).
В Python 3 нельзя конкатенировать байты и строки. Но поскольку в Python 2 bytes является псевдонимом str, это сработает: b'a' + u'b' работает в Python 2, а b'a' + 'b' в Python 3 вызывает TypeError. Аналогичная проблема возникает и при сравнении байтов и строк.
Поддержка только Python 2.5 и новее¶Supporting Python 2.5 and Newer Only
Если вы поддерживаете Python 2.5 и новее, всё ещё есть некоторые возможности Python, которые можно использовать.
from __future__ import absolute_import¶
Неявные относительные импорты (например, импорт spam.bacon из модуля spam.eggs с помощью инструкции import bacon) не работают в Python 3. Это выражение __future__ отходит от такой практики и разрешает использование явных относительных импортов (например, from . import bacon).
В Python 2.5 необходимо использовать инструкцию __future__, чтобы получить возможность использовать явные относительные импорты и предотвратить неявные. В Python 2.6 явные относительные импорты доступны и без этой инструкции, но она всё ещё нужна для предотвращения неявных относительных импортов. В Python 2.7 инструкция __future__ не требуется. Другими словами, если вы не поддерживаете только Python 2.7 или версию старше Python 2.5, используйте инструкцию __future__.
Работа с распространёнными «подводными камнями»¶Handle Common “Gotchas”
Есть несколько моментов, которые постоянно оказываются камнями преткновения для людей, – их 2to3 не может обработать автоматически, или же они легко выполняются в Python 2, чтобы помочь модернизировать код.
from __future__ import division¶
Хотя того же результата можно добиться, используя аргумент -Qnew Python, использование этого future-оператора снимает требование, чтобы пользователи использовали этот флаг для получения ожидаемого поведения деления в Python 3 (например, 1/2 == 0.5; 1//2 == 0).
Указывайте при открытии файла в двоичном режиме¶Specify when opening a file as binary
Если вы не работали в Windows, возможно, вы не всегда утруждали себя добавлением режима b при открытии двоичного файла (например, rb для чтения в двоичном режиме). В Python 3 двоичные файлы и текстовые файлы чётко различаются и взаимно несовместимы; подробнее см. модуль io. Поэтому необходимо принять решение, будет ли файл использоваться для двоичного доступа (чтение и/или запись байтовых данных) или текстового доступа (чтение и/или запись данных Unicode).
Текстовые файлы¶Text files
Текстовые файлы, созданные с помощью open() в Python 2, возвращают байтовые строки, тогда как в Python 3 они возвращают строки Unicode. В зависимости от стратегии переноса это может быть проблемой.
Если требуется, чтобы текстовые файлы возвращали строки Unicode в Python 2, есть две возможности:
- В Python 2.6 и выше используйте io.open(). Поскольку io.open() по сути та же функция и в Python 2, и в Python 3, это поможет устранить любые возможные проблемы.
- Если требуется совместимость с версиями ниже 2.6, тогда используйте codecs.open(). Это гарантирует, что в Python 2 вы получите строки Unicode.
Наследуйте от object¶Subclass object
Классы нового стиля существуют с Python 2.2. Необходимо убедиться, что вы наследуете от object, чтобы избежать странных крайних случаев с порядком разрешения методов и т.д. Это по-прежнему полностью допустимо в Python 3 (хотя и не нужно, так как все классы неявно наследуют от object).
Работа с дихотомией байтов и строк¶Deal With the Bytes/String Dichotomy
Одна из самых больших проблем, с которой сталкиваются люди при переносе кода на Python 3, – это дихотомия байтов и строк. Поскольку в Python 2 тип str мог содержать текстовые данные, люди со временем стали довольно небрежно разграничивать, какие экземпляры str содержат текст, а какие – байты. В Python 3 уже нельзя быть таким беспечным и нужно правильно обрабатывать различие. Ключ к решению этой проблемы – убедиться, что каждый строковый литерал в вашем коде Python 2 синтаксически или функционально помечен как байтовые или текстовые данные. После этого нужно убедиться, что API спроектированы так, чтобы обрабатывать либо конкретный тип, либо быть должным образом полиморфными.
Разметка строковых литералов Python 2¶Mark Up Python 2 String Literals
Первое, что нужно сделать – обозначить каждый строковый литерал в Python 2 как текстовый или байтовый. Если вы поддерживаете только Python 2.6 или новее, это можно сделать, пометив байтовые литералы префиксом b, а текстовые – префиксом u или с помощью future-оператора unicode_literals.
Если ваш проект поддерживает версии Python до 2.6, тогда следует использовать проект six и его функцию b() для обозначения байтовых литералов. Для текстовых литералов можно использовать функцию u() из six или префикс u.
Определите, что будут принимать API¶Decide what APIs Will Accept
В Python 2 было очень легко случайно создать API, который принимал как байтовые, так и текстовые данные. Но в Python 3, благодаря более строгой обработке разнотипных данных, такое свободное использование байтов и текста вместе обычно приводит к ошибкам.
Возьмем словарь {b'a': 'bytes', u'a': 'text'} в Python 2.6. Он создает словарь {u'a': 'text'}, так как b'a' == u'a'. Но в Python 3 эквивалентный словарь создает {b'a': 'bytes', 'a': 'text'}, т.е. без потери данных. Подобные проблемы могут возникать при переносе кода Python 2 на Python 3.
Это означает, что нужно выбрать, что API будет принимать и создавать, и последовательно придерживаться этого API в Python 2 и 3.
Сравнение байтов и Unicode¶Bytes / Unicode Comparison
В Python 3 смешивание байтов и unicode запрещено в большинстве ситуаций; это вызовет TypeError, тогда как Python 2 попытался бы выполнить неявное приведение типов. Однако есть один случай, когда это не так, и это может ввести в заблуждение:
>>> b"" == ""
False
Это потому, что сравнение на равенство по языку всегда должно завершаться успехом (и возвращать False для несовместимых типов). Однако это также означает, что неправильно портированный код на Python 3 может демонстрировать ошибочное поведение, если такие сравнения выполняются незаметно. Для обнаружения таких ситуаций в Python 3 есть флаг -b, который будет показывать предупреждение:
$ python3 -b
>>> b"" == ""
__main__:1: BytesWarning: Comparison between bytes and string
False
Чтобы превратить предупреждение в исключение, используйте флаг -bb:
$ python3 -bb
>>> b"" == ""
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
BytesWarning: Comparison between bytes and string
Индексирование байтовых объектов¶Indexing bytes objects
Еще одно потенциально удивительное изменение – это поведение индексирования байтовых объектов в Python 3:
>>> b"xyz"[0]
120
Действительно, байтовые объекты Python 3 (а также объекты bytearray) являются последовательностями целых чисел. Но код, перенесенный из Python 2, часто предполагает, что индексирование байтовой строки дает другую байтовую строку, а не целое число. Чтобы согласовать оба поведения, используйте срезы:
>>> b"xyz"[0:1]
b'x'
>>> n = 1
>>> b"xyz"[n:n+1]
b'y'
Единственная оставшаяся ловушка в том, что выход за границы при срезе возвращает пустой байтовый объект вместо возбуждения IndexError:
>>> b"xyz"[3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: index out of range
>>> b"xyz"[3:4]
b''
__str__()/__unicode__()¶
В Python 2 объекты могут определять как строковое, так и unicode представление себя. В Python 3, однако, существует только строковое представление. Это становится проблемой, поскольку люди могут нечаянно делать в своих методах __str__() вещи, которые приводят к непредсказуемым результатам (например, бесконечная рекурсия, если использовать идиому unicode(self).encode('utf8') в качестве тела метода __str__()).
Есть два способа решить эту проблему. Первый – использовать пользовательский фиксер 2to3. В блоге по адресу http://lucumr.pocoo.org/2011/1/22/forwards-compatible-python/ описывается, как это сделать. Это позволит 2to3 заменить все вхождения def __unicode(self): ... на def __str__(self): .... Для этого требуется, чтобы метод __str__() был определён в Python 2 перед методом __unicode__().
Другой вариант – использовать примесь (mixin class). Это позволяет определить только метод __unicode__() для вашего класса, а примесь сама сгенерирует __str__() (код из http://lucumr.pocoo.org/2011/1/22/forwards-compatible-python/):
import sys
class UnicodeMixin(object):
"""Миксин-класс для определения правильных методов __str__/__unicode__
методов в Python 2 или 3.
if sys.version_info[0] >= 3: # Python 3
def __str__(self):
return self.__unicode__()
else: # Python 2
def __str__(self):
return self.__unicode__().encode('utf8')
class Spam(UnicodeMixin):
def __unicode__(self):
return u'spam-spam-bacon-spam' # 2to3 удалит префикс 'u'.
Не индексируйте исключения¶Don’t Index on Exceptions
В Python 2 следующее работало:
>>> exc = Exception(1, 2, 3)
>>> exc.args[1]
2
>>> exc[1] # Только Python 2!
2
Но в Python 3 индексирование непосредственно исключения является ошибкой. Необходимо убедиться, что индексирование производится только по атрибуту BaseException.args, который представляет собой последовательность, содержащую все аргументы, переданные методу __init__().
Еще лучше использовать документированные атрибуты, которые предоставляет исключение.
Не используйте __getslice__ и компанию¶Don’t use __getslice__ & Friends
Уже некоторое время считалось устаревшим, но Python 3 наконец отказался от поддержки __getslice__() и т.д. Полностью переходите на __getitem__() и ее друзей.
Обновление doctest-ов¶Updating doctests
2to3 попытается сгенерировать исправления для доктестов, которые встретит. Однако это не идеально. Если вы написали монолитный набор доктестов (например, одну строку документации, содержащую все доктесты), стоит хотя бы рассмотреть разбивку доктестов на более мелкие части, чтобы их было легче исправлять. В противном случае может быть вполне оправданно потратить время и усилия на перенос тестов на unittest.
Обновление map для несбалансированных входных последовательностей¶Update map for imbalanced input sequences
В Python 2 map дополнял входные последовательности неравной длины значениями None, возвращая последовательность длиной, равной длине самой длинной входной последовательности.
В Python 3, если входные последовательности для map имеют разную длину, map остановится по достижении конца самой короткой последовательности. Для полной совместимости с map из Python 2.x оберните последовательности в itertools.zip_longest(), например: map(func, *sequences) превращается в list(map(func, itertools.zip_longest(*sequences))).
Устранение -3 предупреждений¶Eliminate -3 Warnings
При запуске набора тестов вашего приложения запускайте его с флагом -3, передаваемым Python. Это вызовет появление различных предупреждений во время выполнения о том, что 2to3 не может обработать автоматически (например, удалённые модули). Старайтесь устранять эти предупреждения, чтобы сделать ваш код ещё более переносимым на Python 3.
Запуск 2to3¶Run 2to3
После того как ваш код Python 2 стал совместимым с Python 3 на будущее, пора использовать 2to3 для непосредственного переноса кода.
Вручную¶Manually
Чтобы вручную преобразовать исходный код с помощью 2to3, используйте сценарий 2to3, который устанавливается вместе с Python 2.6 и новее.:
2to3 <directory or file to convert>
Это заставит 2to3 вывести diff со всеми применёнными фиксерами для преобразованного исходного кода. Если вы хотите, чтобы 2to3 сразу применил изменения, передайте ему флаг -w:
2to3 -w <stuff to convert>
Доступны и другие флаги для управления тем, какие именно фиксеры применяются, и т. д.
Во время установки¶During Installation
Когда пользователь устанавливает ваш проект для Python 3, можно поручить либо distutils, либо Distribute запустить 2to3 от вашего имени. Для distutils используйте следующий шаблон:
try: # Python 3
from distutils.command.build_py import build_py_2to3 as build_py
except ImportError: # Python 2
from distutils.command.build_py import build_py
setup(cmdclass = {'build_py': build_py},
# ...
)
Для Distribute:
setup(use_2to3=True,
# ...
)
Это позволит вам не распространять отдельную версию проекта для Python 3. Однако это требует, чтобы при разработке вы хотя бы собирали проект и использовали собранный исходный код Python 3 для тестирования.
Проверка и тестирование¶Verify & Test
К этому моменту ваш проект, вероятно, уже преобразован так, что работает в Python 3. Проверьте это, запустив модульные тесты и убедившись, что ничего не пошло не так. Если что-то упущено, выясните, как исправить это в Python 3, перенесите исправление обратно в код Python 2 и снова прогнать код через 2to3, чтобы убедиться, что исправление преобразуется правильно.
Исходный код, совместимый с Python 2/3¶Python 2/3 Compatible Source
Хотя это может показаться нелогичным, можно писать код Python, который будет совместим на уровне исходного кода между Python 2 и 3. Это приводит к коду, который не является полностью идиоматическим Python (например, необходимость извлекать текущее вызванное исключение из sys.exc_info()[1]), но его можно запускать как в Python 2, так и в Python 3 без использования 2to3 в качестве этапа трансляции (хотя этот инструмент следует использовать для поиска потенциальных проблем переносимости). Это позволяет сохранять быстрый процесс разработки независимо от того, разрабатываете ли вы под Python 2 или Python 3. Какой подход – этот или использование Python 2 и 2to3 – подходит вам лучше, решается для каждого проекта индивидуально.
Чтобы получить полное представление о том, с какими проблемами придётся столкнуться, обратитесь к разделу What’s New in Python 3.0. Другие люди переорганизовали данные в других форматах, например, http://docs.pythonsprints.com/python3_porting/py-porting.html.
Ниже описаны некоторые шаги, которые помогут попытаться поддерживать и Python 2, и 3 из одного исходного кода.
Следуйте инструкциям по использованию 2to3¶Follow The Steps for Using 2to3
Все шаги, описанные в разделе о том, как портировать код Python 2 с помощью 2to3, применимы и к созданию кодовой базы для Python 2/3. Это включает в себя попытку поддерживать только Python 2.6 или новее (инструкции __future__ работают в Python 3 без проблем), устранение предупреждений, возникающих из-за -3, и так далее.
Стоит даже рассмотреть запуск 2to3 на вашем коде (без фиксации изменений). Это позволит узнать, где в коде находятся потенциально проблемные места, чтобы исправить их должным образом, прежде чем они станут серьёзной проблемой.
Используйте six¶Use six
Проект six содержит множество средств для написания переносимого кода на Python. Обязательно прочитайте его документацию от начала до конца и используйте все предоставляемые им возможности. Так вы минимизируете количество ошибок, которые могут возникнуть при написании кода, совместимого с разными версиями.
Перехват текущего возбуждённого исключения¶Capturing the Currently Raised Exception
Одно из изменений между Python 2 и 3, которое потребует изменения подхода к написанию кода (если вы поддерживаете Python 2.5 и более ранние версии), касается доступа к текущему возбуждённому исключению. В Python 2.5 и более ранних версиях синтаксис для доступа к текущему исключению был таким:
try:
raise Exception()
except Exception, exc:
# Текущее исключение: 'exc'
pass
Этот синтаксис изменился в Python 3 (и был перенесён в Python 2.6 и новее) на:
try:
raise Exception()
except Exception as exc:
# Текущее исключение: 'exc'
# В Python 3 'exc' ограничен блоком; в Python 2.6 оно будет "утекать"
pass
Из-за этого изменения синтаксиса нужно перейти на захват текущего исключения следующим образом:
try:
raise Exception()
except Exception:
import sys
exc = sys.exc_info()[1]
# Текущее исключение: 'exc'
pass
Из sys.exc_info() можно получить больше информации о возбуждённом исключении, чем просто экземпляр текущего исключения, но, скорее всего, она не нужна.
Примечание
В Python 3 трассировка прикрепляется к экземпляру исключения через атрибут __traceback__. Если экземпляр сохраняется в локальной переменной, которая существует за пределами блока except, трассировка создаст циклическую ссылку с текущим фреймом и его словарём локальных переменных. Это задержит освобождение мёртвых ресурсов до следующего прохода циклической сборки мусора.
В Python 2 эта проблема возникает только в том случае, если сохранить саму трассировку (например, третий элемент кортежа, возвращаемого sys.exc_info()) в переменной.
Другие ресурсы¶Other Resources
Авторы следующих записей в блогах, страниц вики и книг заслуживают особой благодарности за то, что опубликовали свои советы по портированию кода Python 2 на Python 3 (и тем самым помогли предоставить информацию для этого документа):
- http://python3porting.com/
- http://docs.pythonsprints.com/python3_porting/py-porting.html
- http://techspot.zzzeek.org/2011/01/24/zzzeek-s-guide-to-python-3-porting/
- http://dabeaz.blogspot.com/2011/01/porting-py65-and-my-superboard-to.html
- http://lucumr.pocoo.org/2011/1/22/forwards-compatible-python/
- http://lucumr.pocoo.org/2010/2/11/porting-to-python-3-a-guide/
- http://wiki.python.org/moin/PortingPythonToPy3k
Если вы считаете, что в этом документе чего-то не хватает и это следует добавить, отправьте письмо в список рассылки python-porting.