Я делаю последние штрихи примерно на 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