如何编写适用于Python 2和Python 3的代码? [英] How to write code that works in both Python 2 and Python 3?

查看:69
本文介绍了如何编写适用于Python 2和Python 3的代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

 #Python 2使用'iteritems'
def log_dict(* * kwargs):
作为密钥,kwargs.iteritems()中的值:
log.info( {0}:{1}。format(key,value))

#Python 3使用'items'
def log_dict(** kwargs):
作为密钥,kwargs.items()中的值:
log.info( {0}:{ 1}。format(key,value))


解决方案

官方文档提出了执行此操作的方法的建议。由于情况的变化,该文档也随着时间的推移而发生了变化,因此值得直接去参考(特别是如果您在撰写此答案后的一两年内阅读此答案)。



也值得阅读保守的Python 3移植指南,并略读Nick Coghlan的Python 3问题与解答,尤其是本部分



从2018年初开始回顾:



进一步完善



当前的官方建议是:




  • 只担心支持Python 2.7

  • 确保您具有良好的测试覆盖范围( coverage.py 可以提供帮助; 点安装范围

  • 了解Python 2和amp;之间的区别3

  • 使用 Futurize (或现代化)以更新您的代码(例如 pip安装将来

  • 使用 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中可用。这是如此明显,以至于他们似乎忘记了将其排除在文档之外,但是,除了使您的生活更轻松(例如,您可以编写 print 函数调用)之外,未来化现代化(以及六个 sixer )是必需的。



六个



文档针对的是人们在不久的将来不可逆转地过渡到Python 3。如果您打算长期使用双版本代码,则可能遵循先前的建议会更好,因为以前的建议主要围绕使用六个而不是将来。六本书涵盖了两种语言之间的更多差异,还使您编写了明确的关于双版本的代码,而不是在2.7中仍能尽可能地接近Python 3。但是缺点是,您实际上在做两个端口-一个从2.7到基于六个版本的双版本代码,然后从仅3.x的六个代码到仅3.x的本机代码。 / p>

2to3



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



2to3上还有两个变体: sixer 自动移植Python 2.7代码转换为使用6的双版本代码,并且 3to2 可让您为Python 3和自动代码编写代码-在安装时将端口改回2.7。两者都曾一度流行,但似乎已不再使用。






对于您的特定问题,




  • kwargs.items()都可以使用,如果您不介意2.7中的次要性能成本。

  • 2to3可以在安装时自动将 items 更改为 items .x。

  • futurize可以用来完成上述任一操作。

  • 6个将允许您编写 6个。 iteritems(kwargs),它将在2.7和 items 中执行 itemsms

  • six还将允许您编写 six.viewitems(kwargs),它将执行 viewitems 在2.7中(与在3.x中相同,而不仅仅是相似)。

  • modifyize和sixer会自动将 kwargs.iteritems()更改为 six.iteritems(kwargs)

  • 3to2将使您编写 kwargs.items()并在安装时在2.x上自动将其转换为 viewitems

  • mypy可以验证您是否正在使用结果作为一般可迭代的(而不是专门作为迭代器),因此更改为 viewitems items 正确键入。


A Django website I maintain currently uses Python 2.7 but I know that I'll have to upgrade it to Python 3 in a couple of months. If I'm writing code right now that has to work in Python 2, is there a Pythonic way to write it such that it would also work in Python 3 without any changes if I know what the syntax is going to be in Python 3? Ideally I'd like the code to continue to work even after the upgrade without changing it but it would be easy for me to spot where I've done this in the codebase so that I can change the code when I have time. Here's an example of what I'm talking about:

# 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))

解决方案

There is official documentation suggesting ways to do this. That documentation has changed over time as the situation has changed, so it's worth going directly to the source (especially if you're reading this answer a year or two after it was written).

It's also worth reading the Conservative Python 3 Porting Guide and skimming Nick Coghlan's Python 3 Q&A, especially this section.

Going back in time from the early 2018:

futurize

The current official suggestions are:

  • Only worry about supporting Python 2.7
  • Make sure you have good test coverage (coverage.py can help; pip install coverage)
  • Learn the differences between Python 2 & 3
  • Use Futurize (or Modernize) to update your code (e.g. pip install future)
  • Use Pylint to help make sure you don’t regress on your Python 3 support (pip install pylint)
  • Use caniusepython3 to find out which of your dependencies are blocking your use of Python 3 (pip install caniusepython3)
  • Once your dependencies are no longer blocking you, use continuous integration to make sure you stay compatible with Python 2 & 3 (tox can help test against multiple versions of Python; pip install tox)
  • Consider using optional static type checking to make sure your type usage works in both Python 2 & 3 (e.g. use mypy to check your typing under both Python 2 & Python 3).

Notice the last suggestion. Guido and another of the core devs have both been heavily involved in leading large teams to port large 2.7 codebases to 3.x, and found mypy to be very helpful (especially in dealing with bytes-vs.-unicode issues). In fact, that's a large part of the reason gradual static typing is now an official part of the language.

You also almost certainly want to use all of the future statements available in 2.7. This is so obvious that they seem to have forgotten to leave it out of the docs, but, besides making your life easier (e.g., you can write print function calls), futurize and modernize (and six and sixer) require it.

six

The documentation is aimed at people making an irreversible transition to Python 3 in the near future. If you're planning to stick with dual-version code for a long time, you might be better off following the previous recommendations, which largely revolved around using six instead of futurize. Six covers more of the differences between the two languages, and also makes you write code that's explicit about being dual-version instead of being as close to Python 3 as possible while still running in 2.7. But the downside is that you're effectively doing two ports—one from 2.7 to six-based dual-version code, and then, later, from 3.x-only six code to 3.x-only "native" code.

2to3

The original recommended answer was to use 2to3, a tool that can automatically convert Python 2 code to Python 3 code, or guide you in doing so. If you want your code to work in both, you need to deliver Python 2 code, then run 2to3 at installation time to port it to Python 3. Which means you need to test your code both ways, and usually modify it so that it still works in 2.7 but also works in 3.x after 2to3, which isn't always easy to work out. This turns out to not be feasible for most non-trivial projects, so it's no longer recommended by the core devs—but it is still built in with Python 2.7 and 3.x, and getting updates.

There are also two variations on 2to3: sixer auto-ports your Python 2.7 code to dual-version code that uses six, and 3to2 lets you write your code for Python 3 and auto-port back to 2.7 at install time. Both of these were popular for a time, but don't seem to be used much anymore; modernize and futurize, respectively, are their main successors.


For your specific question,

  • kwargs.items() will work on both, if you don't mind a minor performance cost in 2.7.
  • 2to3 can automatically change that iteritems to items at install time on 3.x.
  • futurize can be used to do either of the above.
  • six will allow you to write six.iteritems(kwargs), which will do iteritems in 2.7 and items in 3.x.
  • six will also allow you to write six.viewitems(kwargs), which will do viewitems in 2.7 (which is identical to what items does in 3.x, rather than just similar).
  • modernize and sixer will automatically change that kwargs.iteritems() to six.iteritems(kwargs).
  • 3to2 will let you write kwargs.items() and autmatically convert it to viewitems at install time on 2.x.
  • mypy can verify that you're just using the result as a general iterable (rather than specifically as an iterator), so changing to viewitems or items leaves your code still correctly typed.

这篇关于如何编写适用于Python 2和Python 3的代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆