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

如何尽早获得控制权以发出错误消息 并退出吗?

For example, I have a program that uses the ternery operator (new in 2.5) and "with" blocks (new in 2.6). I wrote a simple little interpreter-version checker routine which is the first thing the script would call ... except it doesn't get that far. Instead, the script fails during python compilation, before my routines are even called. Thus the user of the script sees some very obscure synax error tracebacks - which pretty much require an expert to deduce that it is simply the case of running the wrong version of 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

(为同事通灵。)


你可以使用eval进行测试:

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

此外,with在Python 2.5中可用,只需从__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 *

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

eg:

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

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


Try

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

问题很简单。您检查了版本是否小于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文件形式的已编译版本可用)会发生编译步骤,这时您会得到错误,而不是(确切地说)当代码正在运行时。

You can put off the compile step and make it happen at run time for a single line of code, if you want to, by using eval, as noted above, but I personally prefer to avoid doing that, because it causes Python to perform potentially unnecessary run-time compilation, for one thing, and for another, it creates what to me feels like code clutter. (If you want, you can generate code that generates code that generates code - and have an absolutely fabulous time modifying and debugging that in 6 months from now.) So what I would recommend instead is something more like this:

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,你可以自己决定是否有条件地使用新语法。


尽管问题是 我如何尽早获得控制以发出错误消息并退出?

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

我的回答和其他帖子有很大不同。 到目前为止,似乎答案都试图从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

我的hack版本是:

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


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

我喜欢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的回答:

您还可以使用标准库中的平台模块从代码本身检查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:


有用的资源

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版本


你可以和系统确认。Hexversion或sys.version_info。

sys。十六进制对人类不是很友好,因为它是十六进制数。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 # '''

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

这种解决方案的优点是,如果使用的是3.6以上的Python版本,像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