一个Python脚本能同时在Python 2.x和Python 3.x上运行吗?

8

我有数千台服务器(linux),有些只有python 2.x,有些只有python 3.x。我想编写一个名为check.py的脚本,可以在所有服务器上运行,就像$./check.py一样,而不需要使用$python check.py或$python3 check.py。有没有办法做到这一点?

我的问题是如何让脚本check.py找到解释器,无论解释器是python2.x还是python3.x。


2
当然可以...只要您使用两种语言都通用的语言结构。 - Joran Beasley
问题是如何编写第一行 #/usr/bin/env python[2.x|3.x] 来查找解释器。 - xielingyun
为什么这是个问题?只需在一个只有2.x或同时拥有2.x和3.x的系统上运行python,那将是2.x;在一个只有3.x的系统上,它应该是3.x。 - abarnert
哈哈...我犯了个错误,你是对的,只需要使用 #/usr/bin/env python 就足够了,谢谢。 - xielingyun
@abarnert请不要概括:至少在Arch Linux上,情况恰恰相反:python == Python 3.x,python2 == Python 2.x。 - ack
@ack:根据 PEP 394,Arch Linux 在2011-2014年期间做错了事情,这是一个已知的问题(事实上,这也是PEP编写的主要原因)。但是,即使考虑了Arch,评论仍然是有效的:在只有2.x或同时拥有2.x和3.x的系统上运行python将使用2.x;在只有3.x或同时拥有两者的Arch系统上运行它应该是3.x。只要您编写了兼容双方的代码,它就可以正常工作。 - abarnert
3个回答

16

许多脚本可以在2.x和3.x上运行(我每天都在处理一堆这样的脚本,还将各种开源库从2.x改为支持双版本)。

以下几点会使它更容易:

  • 对于2.x用户,请要求使用2.7或至少2.6+。否则,例如,您无法使用参数引发异常或将其捕获到变量中等诸多限制。
  • 对于3.x用户,请要求使用3.3+或至少3.2+。大多数无关紧要的不兼容性(如取消了前缀u)在3.2或3.3中被撤消了。
  • 使用six库。
  • 使用__future__语句。
  • 始终清楚地知道您的意思是bytes(始终为8位)、unicode(如果要得到8位,则必须编码)还是str(大多数标准库API所需的内容),并根据需要进行encodedecode
  • 定期在代码上运行2to3。(但不要盲目执行它说的所有操作。如果,例如,您正在使用d.keys()map(f, l),因为您不关心是否返回list,那么您会收到警告,因为2to3 不知道您不关心)。

或者,不要尝试编写可同时运行于两个版本的代码,而是编写运行于2.x但可以自动转换为3.x代码的代码,并将其作为安装过程的一部分(在setup.py中,如果sys.version_info >= (3, 0)则执行2to3步骤)。

从您的编辑内容看,似乎您主要关注要在#!行中放什么。对于这个问题:

/usr/bin/env python

不能保证此方法一定有效,但是env的功能本来就没有保证。你可以肯定:

  • 对于几乎任何只提供2.x版本的系统,python都是Python 2。
  • 对于几乎任何同时提供两个版本的系统,python都是Python 2。
  • 对于几乎任何只提供3.x版本的系统(目前非常少见,但未来可能会更普遍),python都是Python 3。

然而:

  • 如果系统既没有提供2.x,也没有提供3.x版本,如果管理员只安装了3.x版本,则它很可能在2013年初之后不再作为python可用。这个问题没有什么好的解决办法。

如果以上情况成为一个严重问题,您可以通过添加一个 sh 脚本的启动器来解决,在其中尝试使用 pythonpython3 运行您的程序。

比较好的方式是在您的 Python 脚本中指定启动器脚本作为 shebang 解释器。Linux 可以处理这个问题,但这是可以配置的,至少有些发行版默认禁用它,而大多数其他 *nix 系统则不能使用它。

如果那种方式不起作用,下一个最好的选择是让用户运行启动器脚本,即告诉他们要做./check.sh而不是./check.py,然后check.sh为用户找到正确的 Python 解释器并运行$python ./check.py

如果您想要更加巧妙地解决问题,甚至可以将 Python 脚本嵌入到 shell 脚本中,这样您只需要分发一个文件。他们运行./check.sh,它会找到正确的 Python 并在 heredoc 上运行。


谢谢,我只是想这样做,但这不是我的问题,我认为只有使用Python3才能运行 #!/usr/bin/env python3,否则会出错。 - xielingyun
@xielingyun:大多数流行的平台要么只安装2.x,要么同时安装两个版本。但是有一些系统没有预装Python,正如我所说,如果管理员只安装了3.x(特别是如果他从python.org安装而不是使用发行版软件包),它可能不会作为“python”可用。这对您来说是一个严重的问题吗?如果是,您正在处理什么平台? - abarnert
@xielingyun:我编辑了答案并提供了一些通用的帮助,但正如我所说,它不适用于所有平台。 - abarnert
RHEL 6.x现在有Python 2.x,但也许会在几年后删除Python 2.x,我想解决这个问题。现在我有其他Linux发行版(不是工作平台,所以不需要解决这个问题),没有Python 2.x并遇到了这个问题。所有平台都可以使用shell脚本,但我认为如果发行版没有python,只需执行ln python3 python就更好了。 - xielingyun
只是担心十年之后的问题,现在不是真正的问题。 - xielingyun
显示剩余5条评论

1
考虑到Python 3.x与Python 2.x并不完全向后兼容,您需要确保脚本与两个版本都兼容。这可以通过使用2to3工具来实现,但最终可能意味着运行两个不同的Python脚本。

0
通常情况下,不行;许多 Python 2 脚本无法在 Python 3 上运行,反之亦然。它们是两种不同的语言。
话虽如此,如果您小心一些,可以编写一个脚本,它将在两个版本下正确运行。有些作者会格外小心,确保他们的脚本在两个版本中兼容,通常使用额外的工具,比如 `six` 库 (这个名字是个双关语;你可以通过"2乘以3"或"3乘以2"得到“6”)。
然而,现在已经是2020年了,Python 2 已经正式死亡。许多维护者在 Python 2 还受支持的时候曾经努力维护 Python 2 的兼容性,但现在他们将松一口气,并且常常很高兴地放弃它的继续使用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接