python - 如何编写适用于Python 2和Python 3的代码?

标签 python django python-3.x

我维护的Django网站目前使用Python 2.7,但我知道我将在几个月后将其升级到Python 3。如果我现在正在编写必须在Python 2中工作的代码,是否有Pythonic的方式编写它,以便如果我知道Python 3中的语法,它也可以在Python 3中工作而无需进行任何更改?理想情况下,我希望代码即使在升级后也可以继续工作而不更改它,但是对我而言,很容易在代码库中发现我在哪里进行了此工作,以便我有空时可以更改代码。这是我正在谈论的示例:

# Python 2 uses 'iteritems'
def log_dict(**kwargs):
    for key, value in kwargs.iteritems():
        log.info("{0}: {1}".format(key, value))

# Python 3 uses 'items'
def log_dict(**kwargs):
    for key, value in kwargs.items():
        log.info("{0}: {1}".format(key, value))

最佳答案

official documentation建议执行此操作的方法。随着情况的变化,该文档也随着时间的推移而发生了变化,因此值得直接查阅源文件(特别是如果您在撰写此答案后的一两年内正在阅读此答案)。

还值得阅读Conservative Python 3 Porting Guide并略读Nick Coghlan的Python 3 Q&A,尤其是this section

从2018年初的时光倒流:

future

当前的官方建议是:

  • 只担心支持Python 2.7
  • 确保您具有良好的测试覆盖率(coverage.py可以帮助您; pip install coverage)
  • 了解Python 2和3之间的区别
  • 使用Futurize(或Modernize)更新您的代码(例如pip install future)
  • 使用Pylint可以确保您不依赖Python 3支持(pip install pylint)
  • 使用caniusepython3找出哪些依赖项阻止了对Python 3(pip install caniusepython3)的使用
  • 一旦您的依赖关系不再受阻,请使用持续集成以确保您与Python 2和3兼容(tox可帮助测试多个Python版本; pip install tox)
  • 考虑使用可选的静态类型检查,以确保您的类型用法在Python 2和3中都可以使用(例如,使用mypy来检查您在Python 2和Python 3中的键入)。

  • 注意最后的建议。 Guido和另一位核心开发人员都曾大量参与领导大型团队将2.7的大型代码库移植到3.x,并发现mypy非常有用(特别是在处理bytes-vs.-unicode问题时)。实际上,这是渐进静态类型现在成为该语言的正式组成部分的很大一部分原因。

    您几乎还肯定要使用2.7中提供的所有 future 语句。这是如此明显,以至于他们似乎忘记了将其排除在文档之外,但是除了使您的生活更轻松(例如,您可以编写print函数调用)之外,futurizemodernize(以及sixsixer)也需要它。



    该文档的目标读者是在不久的将来向Python 3不可逆转的过渡。如果您打算长时间坚持使用双版本代码,则最好遵循以前的建议,这些建议主要围绕使用six而不是将来进行。六本书涵盖了两种语言之间的更多差异,并且还使您编写的代码清楚地说明了双版本,而不是在仍以2.7运行时尽可能接近Python 3。但是不利的是,您实际上在做两个端口-一个从2.7到基于六个版本的双版本代码,然后从仅3.x的六个代码到仅3.x的“ native ”代码。

    2对3

    最初建议的答案是使用2to3,该工具可以自动将Python 2代码转换为Python 3代码,或指导您这样做。如果您希望您的代码在这两种代码中都能工作,则需要交付Python 2代码,然后在安装时运行2to3以将其移植到Python3。这意味着您需要同时测试两种代码,并且通常需要对其进行修改以便仍在2.7中可以使用,但在2to3之后也可以在3.x中使用,但这并不总是很容易解决。事实证明,这对于大多数不重要的项目而言是不可行的,因此核心开发人员不再建议使用它,但是它仍然内置在Python 2.7和3.x中并获取更新。

    2to3上还有两个变体:sixer自动将Python 2.7代码移植为使用六个版本的双版本代码,3to2允许您为Python 3编写代码并在安装时自动移植回2.7。两者都曾一度流行,但似乎已不再使用。现代化和 future 化分别是它们的主要继任者。

    对于您的具体问题,

    如果您不介意2.7的性能降低,
  • kwargs.items()可以同时使用。
  • 2to3可以在安装时在3.x上自动将iteritems更改为items
  • futurize可以用来执行以上任一操作。
  • 6将允许您编写six.iteritems(kwargs),它将在2.7中执行iteritems并在3.x中执行items
  • 6也将允许您编写six.viewitems(kwargs),它将在2.7中执行viewitems(这与items在3.x中的功能相同,而不仅仅是相似的功能)。
  • modernize和sixer将自动将该kwargs.iteritems()更改为six.iteritems(kwargs)
  • 3to2将允许您编写kwargs.items()并在安装时在2.x上自动将其转换为viewitems
  • mypy可以验证您只是将结果用作常规可迭代项(而不是专门用作迭代器),因此更改为viewitemsitems可使您的代码仍正确键入。
  • 关于python - 如何编写适用于Python 2和Python 3的代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50079311/

    相关文章:

    python - 灵敏度特异性图 python

    python - Django管理外键字段导致性能问题

    python - 对于模型使用自定义方法而不是 __unicode__/__str__ ?

    python - 如何在 matplotlib 中创建非线性颜色条刻度

    python-3.x - 如何在 win32 错误消息中读取 EXCEPINFO 元组?

    python - 如何更快地求和范围值

    python - 如何使从 map 边缘生成的对象沿着对角线向中间移动?

    python - 如何让 pytest 忽略返回非零代码并写入 stderr 的特定子进程调用?

    python - 我的素数程序中的指数抛出内存错误,我该如何解决?

    python - Django,创建 View : pass form argument to reverse_lazy