Документация Python неофициальный перевод
Содержание страницы

Перенос кода с Python 2 на Python 3Porting 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 и 3to2Python 3 and 3to2

Если вы начинаете новый проект или ваша кодовая база достаточно мала, возможно, стоит рассмотреть написание кода для Python 3 и обратный перенос на Python 2 с помощью 3to2. Благодаря тому, что Python 3 более строг в некоторых вещах, чем Python 2 (например, байты и строки), трансляция исходного кода может быть проще и прямолинейнее, чем с Python 2 на 3. Кроме того, это даёт вам более непосредственный опыт разработки на Python 3, что, поскольку это будущее Python, хорошо в долгосрочной перспективе.

Недостаток этого подхода в том, что 3to2 – сторонний проект. Это означает, что основные разработчики Python (а значит, и данное руководство) не могут давать никаких гарантий относительно того, насколько хорошо 3to2 работает в любой момент времени. Однако нет оснований полагать, что 3to2 – некачественный проект.

Python 2 и 2to3Python 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.7Support 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.

Наследуйте от objectSubclass 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 2Mark Up Python 2 String Literals

Первое, что нужно сделать – обозначить каждый строковый литерал в Python 2 как текстовый или байтовый. Если вы поддерживаете только Python 2.6 или новее, это можно сделать, пометив байтовые литералы префиксом b, а текстовые – префиксом u или с помощью future-оператора unicode_literals.

Если ваш проект поддерживает версии Python до 2.6, тогда следует использовать проект six и его функцию b() для обозначения байтовых литералов. Для текстовых литералов можно использовать функцию u() из six или префикс u.

Определите, что будут принимать APIDecide 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.

Сравнение байтов и UnicodeBytes / 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.

Запуск 2to3Run 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/3Python 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 из одного исходного кода.

Следуйте инструкциям по использованию 2to3Follow The Steps for Using 2to3

Все шаги, описанные в разделе о том, как портировать код Python 2 с помощью 2to3, применимы и к созданию кодовой базы для Python 2/3. Это включает в себя попытку поддерживать только Python 2.6 или новее (инструкции __future__ работают в Python 3 без проблем), устранение предупреждений, возникающих из-за -3, и так далее.

Стоит даже рассмотреть запуск 2to3 на вашем коде (без фиксации изменений). Это позволит узнать, где в коде находятся потенциально проблемные места, чтобы исправить их должным образом, прежде чем они станут серьёзной проблемой.

Используйте sixUse 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 (и тем самым помогли предоставить информацию для этого документа):

Если вы считаете, что в этом документе чего-то не хватает и это следует добавить, отправьте письмо в список рассылки python-porting.