Ответ 1
Вы должны проверить six, библиотеку, которая обеспечивает унифицированный интерфейс для разных вещей, которые отличаются между Python 2 и 3.
Я только начинаю новый проект Python, и в идеале я хотел бы предложить поддержку Python 2 и 3 с самого начала, с минимальными затратами на разработку. Мой вопрос: как лучше всего это сделать для новых проектов?
Я сталкивался с проектами, которые запускают 2to3 или даже 3to2, как часть их сценария установки. Кажется, это очень распространенный способ. Однако, кажется, есть несколько разных способов сделать это. Я также сталкивался с распространением.
Существует также возможность написания кода Python 2/Python 3 для полиглота. Несмотря на то, что это кажется ужасной идеей, я заметил, что в последнее время я склонен писать код, более идиоматичный, как код Python 3, хотя я все еще использую его как Python 2. У меня такое чувство, что это помогает моему собственному переходу только тогда, когда наконец наступает день, и он не делает ничего для того, чтобы предложить или хотя бы помочь двойной поддержке.
Большинство проектов, предлагающих двойную поддержку, которые я видел, добавили поддержку Python 3 поздно, поэтому мне особенно любопытно, есть ли лучший способ, который больше подходит для новых проектов, где у вас есть преимущество чистого листа.
Спасибо!
Вы должны проверить six, библиотеку, которая обеспечивает унифицированный интерфейс для разных вещей, которые отличаются между Python 2 и 3.
По моему опыту, это зависит от типа проекта.
Если это библиотека или очень автономное приложение, то в Python 2.7 обычно разрабатывается общий выбор, позволяющий максимально избегать конструкций, устаревших в Python 3.x, и прибегать к автоматизированным тестам для выявления дыр, оставленных py2to3, которые вам придется исправить вручную.
С другой стороны, для реальных приложений будьте готовы постоянно сталкиваться с библиотеками, которые еще не портированы на py3k (иногда важные). В большинстве случаев у вас не будет другого выбора, кроме как перенести библиотеку на Python 3, поэтому, если вы можете себе это позволить, сделайте это. Обычно я не могу, поэтому я не поддерживаю Python 3 для такого рода проектов (но я изо всех сил пытаюсь написать код, который будет легче переносить, когда это будет возможно).
Для обработки Unicode я нашел это видео PyCon 2012 очень информативным. Этот совет хорош как для Python 2.x, так и для 3.x: обрабатывать каждую строку, поступающую извне, как байты и конвертировать в unicode как можно быстрее, а выходные строки конвертировать в байты как можно позже. Есть еще одно очень информативное видео об обработке даты/времени.
[Обновить]
Это старый ответ. На сегодняшний день (2019) нет хорошего обоснования для запуска проекта с использованием Python 2.x, и есть несколько веских причин для переноса старых проектов на Python 3. 7+ и отказа от поддержки Python 2.x.
По моему опыту лучше не использовать библиотеку типа six
; Вместо этого у меня есть один compat.py
для каждого пакета с только необходимым кодом, не похожим на подход Скотта Гриффитса. six
также несет ответственность за поддержку давно ушедших версий Python: правда в том, что жизнь намного проще, когда вы соглашаетесь с тем, что Pythons <= 2.6 и <= 3.2 исчезли. В версии 2.7 есть функции поддержки backported, такие как .view*
методы на dict
, которые работают точно так же, как и их не префиксные версии на Python 3; и Python 3.3 с другой стороны поддерживает префикс u
для строк unicode снова.
Даже для очень существенных пакетов модуль compat.py
, который позволяет другому коду работать без изменений, может быть довольно коротким: вот пример из pika
, что мои коллеги и я помогли сделать 2/3 полиглота. Pika - один из тех проектов, в которых действительно были запутанные внутренние компоненты, смешивающие unicode и 8-битные строки друг с другом, но теперь мы использовали его в производстве на Python 3 уже более 6 месяцев без проблем.
Другая важная вещь - всегда использовать следующие __future__
при разработке:
from __future__ import absolute_import, division, print_function
Я рекомендую использовать unicode_literals
, потому что на обеих платформах есть строки, которые должны быть типа str
. Если вы не используете unicode_literals
, вы можете сделать следующее:
b'123'
- это 8-битный строковый литерал'123'
имеет тип str
на обеих платформахu'123'
- это правильный текст в Unicode на обеих платформах.В любом случае, пожалуйста, не делайте 2to3 при установке/времени сборки пакета; некоторые пакеты, используемые для этого в прошлом - pip install
для этих пакетов потребовалось несколько секунд на Python 2, но ближе к минуте на Python 3.
Выберите 2 или 3, в зависимости от того, какой из ваших любимых ароматов, и сделайте так, чтобы он работал очень хорошо, с модульными тестами. Затем убедитесь, что эти тесты работают после запуска через py2to3 или py3to2. Лучше поддерживать одну версию кода.
Мой личный опыт заключался в том, что проще писать код, который работает без изменений как в Python 2, так и 3, а не полагаться на скрипты 2to3/3to2, которые часто не могут получить правильный перевод.
Возможно, моя ситуация необычна, поскольку я делаю много с байтовыми типами, а у 2to3 есть сложная задача, которая преобразует их, но удобство использования одной базы кода перевешивает гадость наличия нескольких хаков в коде.
В качестве конкретного примера мой модуль bitstring был ранним преобразованием в Python 3, и тот же код используется для Python 2.6/2.7/3.x. Источник - это более 4000 строк кода, и этот бит мне нужен, чтобы заставить его работать для разных основных версий:
# For Python 2.x/ 3.x coexistence
# Yes this is very very hacky.
try:
xrange
for i in range(256):
BYTE_REVERSAL_DICT[i] = chr(int("{0:08b}".format(i)[::-1], 2))
except NameError:
for i in range(256):
BYTE_REVERSAL_DICT[i] = bytes([int("{0:08b}".format(i)[::-1], 2)])
from io import IOBase as file
xrange = range
basestring = str
ОК, это не очень, но это означает, что я могу написать 99% кода в хорошем стиле Python 2, и все модульные тесты по-прежнему передаются для одного и того же кода в Python 3. Этот маршрут не для всех, но это вариант для рассмотрения.
Если вам нужна поддержка Python 2.5 или ранее, использование Distribute и интеграция 2to3, как правило, лучший способ. Но если вам нужно только поддерживать Python 2.6 или новее, я бы сделал код, выполняемый под Python 2 и Python 3 без преобразования. Я бы также использовал библиотеку six, чтобы сделать это проще.