Как написать Python 2.x настолько совместимым с Python 3.x, насколько это возможно? - PullRequest
35 голосов
/ 14 декабря 2011

Существует множество способов включить функции Python 3.x в Python 2.x , поэтому код сценариев Python 2.x может быть легко преобразован в Python 3.x в будущем. Одним из этих примеров является замена оператора print функцией print():

>>> from __future__ import print_function

Есть ли какой-нибудь список или ресурс, который мог бы дать некоторые идеи, как сделать код Python 2.x максимально приближенным к Python 3.x?

Не могли бы вы привести примеры других полезных импортов или определений , которые могут сделать Python 2.x похожим на Python 3.x ?

Предположим, у нас есть последний Python 2.x (на мой взгляд, 2.7.2 на данный момент).

Ответы [ 6 ]

22 голосов
/ 14 декабря 2011

Я делаю последние штрихи примерно на 5000 строк, дедуплицируя программу резервного копирования (http://stromberg.dnsalias.org/~strombrg/backshift/), которая работает на CPython 2. [567], CPython 3. [0123] (3.3 по-прежнему альфа 0),Pypy 1.7 и транк Jython. Я также пробовал IronPython, но это было совсем другое дело - у него не было стандартной библиотеки, поэтому нет любви к обратному смещению. О, и он может использовать Cython для своего внутреннего цикла или psyco - но pypy быстрее, чемлибо, особенно в 32-битных системах.

Во всяком случае, я обнаружил, что для написания кода, который одинаково хорошо работает на 2.x и 3.x, мне нужно было только:

1) print(переменная) работает одинаково на 2.x и 3.x.print (variable1, variable2) этого не делает.В 2.x print (переменная) говорит: «вычислите это выражение в скобках и напечатайте единственный результат, используя оператор print».В 3.x print (переменная) говорит: «вызовите функцию print для этого единственного результата. Так что print ('abc% d% d'% (1, 2)) отлично работает в обоих случаях, потому что это однозначный результат,и оба получают оператор% для форматирования строки.

2) Избегайте восьмеричных констант. Вместо записи 0755, напишите (7 * 64 + 5 * 8 + 5).

3) ДелатьВ двоичном вводе / выводе я использовал свой модуль bufsock. http://stromberg.dnsalias.org/~strombrg/bufsock.html Я бы открыл файл и обернул его с помощью bufsock (или использовал бы класс rawio в модуле). На 2.x этовернул бы строку байтов, закодированных в виде 8-битных символьных строк. В 3.x это вернуло бы объект байтов, который во многом похож на список маленьких целых чисел. Тогда я просто обошел бы один или другой, тестируя с помощью "isinstance (foo, str) "как необходимо, чтобы различать два. Я сделал это, потому что для программы резервного копирования байты - это байты - я не хотел возиться с кодировками, которые мешают надежно сохранять данные, а не со всеми кодировками вокругудачи.

4) При выполнении исключений избегайте ключевого слова "как". IВместо этого используйте EG:

  try:
     self.update_timestamp()
  except (OSError, IOError):
     dummy, utime_extra, dummy = sys.exc_info()
     if utime_extra.errno == errno.ENOENT:

5) Группа модулей была переименована при переходе с 2.x на 3.x.Поэтому попробуйте импортировать любой из них в пустой модуль, например:

try:
   from anydbm import *
except ImportError:
   from dbm import *

... это будет отображаться в модуле отдельно с именем EG adbm.py.Тогда в любое время, когда мне требовалось хранилище значений ключей, я импортировал adbm вместо двух разных вещей, необходимых для 2.x или 3.x напрямую.Тогда я бы выложил все, кроме этого короткого модуля, adbm.py - и тому подобные вещи, которые не понравились.Идея заключалась в том, чтобы сделать все возможное, за исключением правила «все должно быть» в крошечном модуле, по одному исключению на модуль.

6) Это очень помогает настроить автоматические модульные тесты исистемные тесты, которые выполняются в 2.x и 3.x, а затем часто тестируют как минимум на одном интерпретаторе 2.x, а также хотя бы на одном интерпретаторе 3.x.Я также часто запускаю pylint для своего кода, хотя только pylint проверял на соответствие 2.5.x - я начал проект до того, как pylint получил поддержку 3.x.

7) Я установил небольшой модуль "python2x3"у которого есть несколько констант и функций, облегчающих жизнь: http://stromberg.dnsalias.org/svn/python2x3/trunk/python2x3.py

8) Литералы b '' не работают в 2.5, хотя они вроде работают в 2. [67].Вместо того, чтобы пытаться выполнить предварительную обработку или что-то в этом роде, я создал constants_mod.py, в котором было много вещей, которые обычно были бы литералами b '' в 3.x, и преобразовал их из простой строки в любой тип "байтов" для 2.x или 3.x.Таким образом, они конвертируются один раз при импорте модуля, а не снова и снова во время выполнения.Если вы нацеливаетесь на 2. [67]и, возможно, есть лучший способ, но когда я начинал, проект Pypy был совместим только с 2.5, а Jython по-прежнему.

9) В 2.x длинные целые числа имеют суффикс L.В 3.x все целые числа длинные.Поэтому я просто старался избегать как можно больше длинных целых констант;2.x будет продвигать целое число к длине по мере необходимости, так что, похоже, для большинства вещей это работает нормально.

10) Это помогает МНОЖУ иметь кучу интерпретаторов Python для тестирования.Я построил 2. [567]и 3. [0123]и спрятал их в / usr / local / cpython-xy / для удобства тестирования.Я также поместил некоторые Pypy и Jython в / usr / local, опять же для удобства тестирования.Наличие сценария для автоматизации сборок CPython было весьма ценным.

Я считаю, что это были все те искривления, которые требовались мне для получения очень переносимой базы кода Python в нетривиальном проекте.Одно большое упущение в списке, который я написал выше, - это то, что я не пытаюсь использовать объекты Unicode - это то, что кто-то другой, вероятно, более квалифицирован, чтобы комментировать.

HTH

7 голосов
/ 14 декабря 2011

Существует целая глава по этому вопросу в " Портирование на Python 3 ". Также не пропустите приложения, в которых перечислены языковые различия с обходными путями для поддержки обоих языков.

Возможно, вы захотите использовать библиотеку six , хотя это возможно без нее.

7 голосов
/ 14 декабря 2011

Вы должны проверить Портирование кода Python на 3.0 .Хотя он нацелен на портирование, он отвечает по существу на тот же вопрос;ты просто не пойдешь до конца.

4 голосов
/ 14 декабря 2011

Перенос кода Python 2 на Python 3 является частью официальной документации и, хотя и не дает прямого ответа на ваш вопрос, может помочь.

1 голос
/ 29 сентября 2015

Поскольку это еще не было упомянуто: я нашел этот шпаргалку действительно полезным для этой конкретной цели.

1 голос
/ 14 декабря 2011

У меня есть это в верхней части моего шаблона скрипта Python 2.7:

from __future__ import division, print_function
from future_builtins import ascii, filter, hex, map, oct, zip
...