Написание кода на Python 2.7, максимально приближенного к синтаксису Python 3.x

#python #python-3.x

#python #python-3.x

Вопрос:

Поскольку Django пока не поддерживает Python 3.x, я использую Python 2.7. Однако я хотел бы продолжить и начать знакомство с новым синтаксисом Python 3.x настолько, насколько это возможно. Что подводит меня к вопросу:

  • Каков наилучший способ написания кода на Python 2.7, который будет максимально совместим с Python 3.x?

Я знаю, что запуск python -3 приведет

Предупреждаю о несовместимости Python 3.x, которую 2to3 не может тривиально исправить.

Тем не менее, я заинтересован в том, чтобы привыкнуть к синтаксису Python 3.x, все еще используя Python 2.7.

Например, кажется, что я должен использовать следующий импорт в свой код:

 from __future__ import print_function
from __future__ import unicode_literals
from __future__ import division
from __future__ import absolute_import
  

Вышеупомянутые четыре __future__ import инструкции требуются начиная с Python 3.0, но не требуются в 2.7, как описано в документации Python 2.7.3 27.11. Определения будущих инструкций

Что еще?

Комментарии:

1. Одним из недостатков этого подхода является то, что если ваша программа имеет зависимости от пакетов, несовместимых с какой-либо утилитой __future __, ваша программа завершится сбоем, и у вас не будет особого контроля. Например, вы используете один из простых пакетов pypi, и в нем есть «print something». В любом случае, спасибо, это хороший вопрос.

2. @Shekhar: эффект __future__ локализован в модуле, который его импортирует. С инструкцией print проблем нет; from __future__ import print_function функцию могут использовать только модули, которые находятся print() вверху.

Ответ №1:

Многие модули в наши дни переписываются таким образом, чтобы их можно было выполнять как на Python 2, так и на Python 3. Оказывается, это совсем не сложно, и в будущем будет очень легко просто отказаться от поддержки Python 2.

Взгляните на модуль six, который помогает с этой задачей, заключая в капсулу многие различия удобным способом:

Six предоставляет простые утилиты для переноса различий между Python 2 и Python 3.

На его веб-сайте (и, конечно, в коде) перечислено множество способов сделать это возможным.

Ответ №2:

Поместите следующий код в py3k.py модуль и импортируйте его следующим образом: from py3k import * . Вам нужно поместить его в каждый файл, но вы даже можете оставить его там, если никто больше не использует Python 2.x, или вы могли бы просто выполнить поиск и заменить строку импорта пробелом, а затем удалить файл.

 try:
    from future_builtins import *
except ImportError:
    pass

try:
    input = raw_input
    range = xrange
except NameError:
    pass
  

И вот как выглядит мой файл шаблона:

 #!/usr/bin/env python
# -*- coding: utf-8 -*-

"""

"""

from __future__ import division, absolute_import, 
                       print_function, unicode_literals
from utils.py3k import *  # @UnusedWildImport


#
  

Комментарии:

1. Нет необходимости выполнять nested_scopes, generators, with_statement; все они доступны, когда работают фьючерсы py3. Также zip, map, filter следует импортировать из future_builtins вместо этого…

2. Спасибо, не знал о future_builtins . Что вы подразумеваете под «работой фьючерсов py3»?

3. generators , with_statement и nested_scopes уже есть в 2.6, поэтому они не нужны, потому что print_function и unicode_literals будут жаловаться при попытке импорта в 2.5…

4. Ах, также только что было отмечено: from __future__ import должно быть в каждом файле, это не влияет на другие файлы из py3k.py

Ответ №3:

Вам также необходимо использовать новые синтаксисы исключений, т.Е. не более

 try:
     raise Exception, "Message"
except Exception, e:
     pass
  

вместо этого вы должны сделать:

 try:
     raise Exception("Message")
except Exception as e:
     pass
  

Также убедитесь, что вы добавляете во все свои двоичные строки префикс b, т.Е.:

b’Это двоичная строка’

Более полное описание этого раздела см. http://python3porting.com/noconv.html

Комментарии:

1. Одной из главных неприятностей является отсутствие u'string' синтаксиса в 3. За мои деньги ужасное решение.

2. @Marcin: Это вернулось в 3.3.

Ответ №4:

Здесь могут оказать большую помощь многие IDE на Python.

PyCharm, например, может быть настроен для проверки совместимости с любым диапазоном версий,

введите описание изображения здесь

и сообщать о проблемах любого уровня серьезности:

введите описание изображения здесь

Комментарии:

1. Ninja IDE ( ninja-ide.org ) также имеет аналогичный модуль, который поможет вам преобразовать ваш код в 3.X.

Ответ №5:

 try:
    input = raw_input
    range = xrange
except NameError:
    pass
  

На ум приходят два варианта…

Ответ №6:

Я предлагаю вам попробовать будущую библиотеку. С их сайта:

python-future — это недостающий уровень совместимости между Python 2 и Python 3. Это позволяет использовать единую, чистую, совместимую с Python 3.x кодовую базу для поддержки как Python 2, так и Python 3 с минимальными накладными расходами.

Он предоставляет будущим и прошлым пакетам обратные порты функций из Python 3 и 2. Он также поставляется с настраиваемыми скриптами futurize и pasteurize на основе 2to3, которые помогают вам легко конвертировать Py2 или Py3-код для поддержки Python 2 и 3 в единой чистой кодовой базе в стиле Py3, модуль за модулем.

Известными проектами, использующими python-future для совместимости с Python 2/3, являются Mezzanine и ObsPy.

Ответ №7:

Избегая range() и zip() , вместо этого используя xrange() и itertools.izip() .

Комментарии:

1. Проблема с использованием xrange заключается в том, что он отсутствует в Python 3, поэтому у того же кода нет шансов на выполнение там. Если кто-то готов отказаться от возможных преимуществ в производительности xrange , лучше использовать range вместо этого, делая код более совместимым с python 2 и 3

2. @Eli Почему бы не попробовать (как в моем примере), за исключением того, что range = xrange?

3. @Eli: Но, используя xrange и т.д., вы можете затем тривиально запустить 2to3 в коде, в то время как в противном случае вы могли бы делать что-то вроде zip(foo)[2] , что не сработает, поскольку результат в Python 3 не является списком.

4. @Lennart: согласен с 2to3. На самом деле все зависит от подхода, используемого для реализации перехода.