如何在使用新语言特性的程序中检查Python版本?

如果我有一个Python脚本,至少需要一个特定的 在Python版本中,优雅地失败的正确方式是什么 当使用早期版本的Python启动脚本时?< / p >

我如何获得足够早的控制,以发出错误消息 并退出吗?< / p > 例如,我有一个使用ternery操作符(2.5新增)和“with”块的程序 (2.6新增)。我写了一个简单的小解释器版本 检查程序,这是脚本的第一件事 打电话给……但它并没有走到那一步。相反, 脚本在python编译期间失败,在我的例程之前 甚至被称为。这样脚本的用户就会看到一些非常 模糊语法错误回溯-这是非常必要的 专家推断,这只不过是跑步的情况

. Python版本错误

我知道如何检查Python的版本。问题是一些语法在旧版本的Python中是非法的。考虑这个程序:

import sys
if sys.version_info < (2, 4):
raise "must use python 2.5 or greater"
else:
# syntax error in 2.4, ok in 2.5
x = 1 if True else 2
print x

当在2.4下运行时,我想要这个结果

$ ~/bin/python2.4 tern.py
must use python 2.5 or greater

而不是这个结果:

$ ~/bin/python2.4 tern.py
File "tern.py", line 5
x = 1 if True else 2
^
SyntaxError: invalid syntax

(为同事通灵。)

263811 次浏览

你可以使用eval进行测试:

try:
eval("1 if True else 2")
except SyntaxError:
# doesn't have ternary

此外,with 在Python 2.5中可用,只需添加from __future__ import with_statement

编辑:为了尽早获得控制权,你可以将它分割成不同的.py文件,并在导入前检查主文件中的兼容性(例如在包中的__init__.py中):

# __init__.py


# Check compatibility
try:
eval("1 if True else 2")
except SyntaxError:
raise ImportError("requires ternary support")


# import from another module
from impl import *

我认为最好的方法是测试功能而不是版本。在某些情况下,这是微不足道的,但在另一些情况下并非如此。

例如:

try :
# Do stuff
except : # Features weren't found.
# Do stuff for older versions.

只要你在使用try/except块时足够具体,你就可以覆盖大部分基础。

试一试

import platform
platform.python_version()

应该会给你一个像“2.3.1”的字符串。如果这不是你想要的,还有一组丰富的数据可以通过内置的“平台”获得。你想要的东西应该在里面。

为您的程序提供以下包装器。

import sys


req_version = (2,5)
cur_version = sys.version_info


if cur_version >= req_version:
import myApp
myApp.run()
else:
print "Your Python interpreter is too old. Please consider upgrading."

如果你打算遇到使用2.0以前版本Python解释器的人,你也可以考虑使用sys.version(),但你有一些正则表达式要做。

也许有更优雅的方法。

集在Python 2.4中成为核心语言的一部分,以保持向后兼容。我当时就是这么做的,对你也有用:

if sys.version_info < (2, 4):
from sets import Set as set

这个怎么样:

import sys


def testPyVer(reqver):
if float(sys.version[:3]) >= reqver:
return 1
else:
return 0


#blah blah blah, more code


if testPyVer(3.0) == 1:
#do stuff
else:
#print python requirement, exit statement
问题很简单。你检查了版本是否为< em > < < / em > 2.4,不小于或等于。因此,如果Python版本是2.4,则不小于2.4。 你应该得到的是:

    if sys.version_info **<=** (2, 4):

,而不是

    if sys.version_info < (2, 4):

进行版本比较的最好方法可能是使用sys.hexversion。这一点很重要,因为比较版本元组不会在所有python版本中都得到想要的结果。

import sys
if sys.hexversion < 0x02060000:
print "yep!"
else:
print "oops!"

如上所述,语法错误发生在编译时,而不是在运行时。虽然Python是一种“解释型语言”,但Python代码实际上并不是直接解释的;它被编译成字节码,然后进行解释。当导入模块时(如果没有.pyc或.pyd文件形式的已编译版本可用)会发生编译步骤,这时您会得到错误,而不是(确切地说)当代码正在运行时。

你可以推迟编译步骤,让它在运行时发生在一行代码中,如果你想,通过使用eval,如上所述,但我个人更倾向于避免这样做,因为它会导致Python执行潜在不必要的运行时编译,一方面,另一方面,它造成了我感觉像代码混乱的东西。(如果你愿意,你可以生成生成代码的代码,然后生成生成代码的代码——从现在开始的6个月里,你会有一段非常美妙的时间来修改和调试它。)所以我建议你这样做:

import sys
if sys.hexversion < 0x02060000:
from my_module_2_5 import thisFunc, thatFunc, theOtherFunc
else:
from my_module import thisFunc, thatFunc, theOtherFunc

.. 即使我只有一个使用新语法的函数,而且它非常短,我也会这样做。(事实上,我会采取一切合理的措施来减少这类函数的数量和大小。我甚至可以写一个像ifTrueAElseB(cond, a, b)这样的函数,其中只有一行语法。)

另一件可能值得指出的事情(我有点惊讶还没有人指出这一点)是,虽然早期版本的Python不支持类似于

value = 'yes' if MyVarIsTrue else 'no'

..它支持类似

value = MyVarIsTrue and 'yes' or 'no'

这是写三元表达式的老方法。我还没有安装Python 3,但据我所知,这种“旧”方式至今仍然有效,所以如果你需要支持使用旧版本的Python,你可以自己决定是否有条件地使用新语法。

尽管问题是: 我如何获得足够早的控制,以发出错误消息和退出?< / em >

我要回答的问题是: 我如何获得足够早的控制,以发出错误消息在启动应用程序之前?

我可以回答很多不同于其他帖子。 到目前为止,似乎答案都试图从Python中解决你的问题 我说,在启动Python之前进行版本检查。我知道你的路径是Linux或unix。 但是我只能给你一个Windows脚本。我认为把它适应linux脚本语法不会太难

下面是2.7版的DOS脚本:

@ECHO OFF
REM see http://ss64.com/nt/for_f.html
FOR /F "tokens=1,2" %%G IN ('"python.exe -V 2>&1"') DO ECHO %%H | find "2.7" > Nul
IF NOT ErrorLevel 1 GOTO Python27
ECHO must use python2.7 or greater
GOTO EOF
:Python27
python.exe tern.py
GOTO EOF
:EOF

这不会运行应用程序的任何部分,因此不会引发Python异常。它不创建任何临时文件或添加任何操作系统环境变量。它不会因为不同的版本语法规则而导致应用程序出现异常。这样就少了三个安全入口。

FOR /F行是键。

FOR /F "tokens=1,2" %%G IN ('"python.exe -V 2>&1"') DO ECHO %%H | find "2.7" > Nul

为多个python版本检查检查url: http://www.fpschultze.de/modules/smartfaq/faq.php?faqid=17 < / p >

我的hack版本是:

< p >[女士脚本;Python模块启动前检查Python版本 http://pastebin.com/aAuJ91FQ < / p >

我只是在快速搜索后发现了这个问题,同时试图解决自己的问题,我已经提出了一个混合基于上面的一些建议。

我喜欢DevPlayer使用包装器脚本的想法,但缺点是你最终要为不同的操作系统维护多个包装器,所以我决定用python编写包装器,但使用相同的基本“通过运行exe获取版本”逻辑,并提出了这个想法。

我认为它应该适用于2.5版及以上版本。到目前为止,我已经在Linux的2.66、2.7.0和3.1.2以及OS X的2.6.1上测试了它。

import sys, subprocess
args = [sys.executable,"--version"]


output, error = subprocess.Popen(args ,stdout = subprocess.PIPE, stderr = subprocess.PIPE).communicate()
print("The version is: '%s'"  %error.decode(sys.stdout.encoding).strip("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLMNBVCXZ,.+ \n") )

是的,我知道最终的解码/剥线是可怕的,但我只是想快速获取版本号。我要改进一下。

目前这对我来说已经足够好了,但如果有人能改进它(或者告诉我为什么这是一个糟糕的想法),那也很酷。

import sys
# prints whether python is version 3 or not
python_version = sys.version_info.major
if python_version == 3:
print("is python 3")
else:
print("not python 3")

将以下内容放在文件的最上方:

import sys


if float(sys.version.split()[0][:3]) < 2.7:
print "Python 2.7 or higher required to run this code, " + sys.version.split()[0] + " detected, exiting."
exit(1)

然后继续使用正常的Python代码:

import ...
import ...
other code...

Nykakin在AskUbuntu的回答:

你也可以使用标准库中的platform模块从代码本身检查Python版本。

有两个功能:

  • platform.python_version()(返回字符串)。
  • platform.python_version_tuple()(返回元组)。

Python代码

创建一个文件,例如:version.py)

检查版本的简便方法:

import platform


print(platform.python_version())
print(platform.python_version_tuple())

你也可以使用eval方法:

try:
eval("1 if True else 2")
except SyntaxError:
raise ImportError("requires ternary support")

在命令行中运行Python文件:

$ python version.py
2.7.11
('2', '7', '11')

在Windows 10上通过WAMP服务器输出带有CGI的Python:

截图2016-11-16 14.39.01 by Suriyaa Kudo .


有用的资源

  • https://askubuntu.com/questions/505081/what-version-of-python-do-i-have < a href = " https://askubuntu.com/questions/505081/what-version-of-python-do-i-have " > < / >
import sys
sys.version

会得到这样的答案吗

'2.7.6(默认,2016年10月26日,20:30:19)\n[GCC 4.8.4]'

这里2.7.6是version

你可以用sys.hexversionsys.version_info来检查。

sys.hexversion不是很人性化,因为它是一个十六进制数。sys.version_info是一个元组,所以它更人性化。

使用sys.hexversion检查Python 3.6或更新版本:

import sys, time
if sys.hexversion < 0x30600F0:
print("You need Python 3.6 or greater.")
for _ in range(1, 5): time.sleep(1)
exit()

使用sys.version_info检查Python 3.6或更新版本:

import sys, time
if sys.version_info[0] < 3 and sys.version_info[1] < 6:
print("You need Python 3.6 or greater.")
for _ in range(1, 5): time.sleep(1)
exit()

sys.version_info更人性化,但需要更多的字符。我会推荐sys.hexversion,尽管它不太人性化。

我希望这对你有所帮助!

对于独立的 python脚本,下面的模块docstring技巧可以强制使用python版本(这里是v2.7.x)(在*nix上测试)。

#!/bin/sh
''''python -V 2>&1 | grep -q 2.7 && exec python -u -- "$0" ${1+"$@"}; echo "python 2.7.x missing"; exit 1 # '''


import sys
[...]

这应该可以处理缺少的python可执行文件,但是依赖于grep。背景信息见在这里

我正在扩展akhan的优秀答案,它打印了一个有用的信息之前, Python脚本甚至被编译。

如果你想确保脚本在Python 3.6或更新版本中运行,请在Python脚本顶部添加这两行:

#!/bin/sh
''''python3 -c 'import sys; sys.exit(sys.version_info < (3, 6))' && exec python3 -u -- "$0" ${1+"$@"}; echo 'This script requires Python 3.6 or newer.'; exit 1 # '''

(注意:第二行以四个单引号开始,以三个单引号结束。这看起来可能很奇怪,但这不是打字错误。)

这种解决方案的优点是,如果使用的Python版本高于3.6,像print(f'Hello, {name}!')这样的代码不会导致SyntaxError。你会看到这条有用的信息:

This script requires Python 3.6 or newer.

当然,此解决方案仅适用于类unix的shell,并且仅在直接调用脚本(例如:./script.py)并设置了适当的eXecute权限位时才有效。

如果用户使用Python 2 exe运行Python 3脚本,有一个简单的方法可以打印有用的消息:

把这作为第一行代码:

f' Error: This script requires Python 3.6 or later.'

它在Python 3.6+中什么都不做(当引入f-strings时),但在Python 2中编译失败,并在控制台上打印:

File "test.py", line 34
f' Error: Error: This script requires Python 3.6 or later.'
^
SyntaxError: invalid syntax