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

问题:如何在使用新语言功能的程序中检查Python版本?

如果我有一个至少需要特定版本Python的Python脚本,那么使用较早版本的Python启动该脚本时,如何正确地正常失败是什么?

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

例如,我有一个使用ternery运算符(2.5中的新增功能)和“ with”块(2.6中的新增功能)的程序。我写了一个简单的解释程序版本检查程序,这是脚本会调用的第一件事……只是它没有那么远。相反,脚本在python编译期间失败,甚至没有调用我的例程。因此,脚本用户会看到一些非常模糊的synax错误回溯-这几乎需要专家来推断,这只是运行错误版本的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

(引导同事。)

If I have a Python script that requires at least a particular version of Python, what is the correct way to fail gracefully when an earlier version of Python is used to launch the script?

How do I get control early enough to issue an error message and exit?

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.

I know how to check the version of Python. The issue is that some syntax is illegal in older versions of Python. Consider this program:

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

When run under 2.4, I want this result

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

and not this result:

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

(Channeling for a coworker.)


回答 0

您可以使用进行测试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 *

You can test using eval:

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

Also, with is available in Python 2.5, just add from __future__ import with_statement.

EDIT: to get control early enough, you could split it into different .py files and check compatibility in the main file before importing (e.g. in __init__.py in a package):

# __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 *

回答 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."

sys.version()如果您打算遇到使用2.0之前的Python解释器的人员,那么您也可以考虑使用,但是您需要做一些正则表达式。

并且可能会有更优雅的方法来做到这一点。

Have a wrapper around your program that does the following.

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."

You can also consider using sys.version(), if you plan to encounter people who are using pre-2.0 Python interpreters, but then you have some regular expressions to do.

And there might be more elegant ways to do this.


回答 2

尝试

导入平台
platform.python_version()

应该给你一个像“ 2.3.1”这样的字符串。如果这不完全符合您的要求,则可以通过“平台”内置的一组丰富的数据。您想要的东西应该在某个地方。

Try

import platform
platform.python_version()

Should give you a string like “2.3.1”. If this is not exactly waht you want there is a rich set of data available through the “platform” build-in. What you want should be in there somewhere.


回答 3

进行此版本比较的最佳方法可能是使用sys.hexversion。这很重要,因为比较版本元组不会在所有python版本中都提供所需的结果。

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

Probably the best way to do do this version comparison is to use the sys.hexversion. This is important because comparing version tuples will not give you the desired result in all python versions.

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

回答 4

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

回答 5

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输出:


有用的资源

Answer from Nykakin at AskUbuntu:

You can also check Python version from code itself using platform module from standard library.

There are two functions:

  • platform.python_version() (returns string).
  • platform.python_version_tuple() (returns tuple).

The Python code

Create a file for example: version.py)

Easy method to check version:

import platform

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

You can also use the eval method:

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

Run the Python file in a command line:

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

The output of Python with CGI via a WAMP Server on Windows 10:


Helpful resources


回答 6

为了保持向后兼容,集成为Python 2.4核心语言的一部分。那时我做到了,这也将为您工作:

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

Sets became part of the core language in Python 2.4, in order to stay backwards compatible. I did this back then, which will work for you as well:

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

回答 7

尽管问题是: 如何尽早控制并发出错误消息并退出

我回答的问题是: 如何在启动应用程序之前尽早控制控件以发出错误消息

与其他帖子相比,我的回答有很大不同。到目前为止,似乎有答案正在尝试从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异常。它不会创建任何临时文件或添加任何OS环境变量。由于版本语法规则不同,它不会使您的应用程序异常终止。这是三个较少的安全访问点。

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

[MS脚本;Python模块的Python版本检查预启动] http://pastebin.com/aAuJ91FQ

Although the question is: How do I get control early enough to issue an error message and exit?

The question that I answer is: How do I get control early enough to issue an error message before starting the app?

I can answer it a lot differently then the other posts. Seems answers so far are trying to solve your question from within Python.

I say, do version checking before launching Python. I see your path is Linux or unix. However I can only offer you a Windows script. I image adapting it to linux scripting syntax wouldn’t be too hard.

Here is the DOS script with version 2.7:

@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

This does not run any part of your application and therefore will not raise a Python Exception. It does not create any temp file or add any OS environment variables. And it doesn’t end your app to an exception due to different version syntax rules. That’s three less possible security points of access.

The FOR /F line is the key.

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

For multiple python version check check out url: http://www.fpschultze.de/modules/smartfaq/faq.php?faqid=17

And my hack version:

[MS script; Python version check prelaunch of Python module] http://pastebin.com/aAuJ91FQ


回答 8

import sys
sys.version

将会得到这样的答案

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

这里2.7.6是版本

import sys
sys.version

will be getting answer like this

‘2.7.6 (default, Oct 26 2016, 20:30:19) \n[GCC 4.8.4]’

here 2.7.6 is version


回答 9

如上所述,语法错误发生在编译时,而不是运行时。虽然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。

As noted above, syntax errors occur at compile time, not at run time. While Python is an “interpreted language”, Python code is not actually directly interpreted; it’s compiled to byte code, which is then interpreted. There is a compile step that happens when a module is imported (if there is no already-compiled version available in the form of a .pyc or .pyd file) and that’s when you’re getting your error, not (quite exactly) when your code is running.

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

.. which I would do even if I only had one function that used newer syntax and it was very short. (In fact I would take every reasonable measure to minimize the number and size of such functions. I might even write a function like ifTrueAElseB(cond, a, b) with that single line of syntax in it.)

Another thing that might be worth pointing out (that I’m a little amazed no one has pointed out yet) is that while earlier versions of Python did not support code like

value = 'yes' if MyVarIsTrue else 'no'

..it did support code like

value = MyVarIsTrue and 'yes' or 'no'

That was the old way of writing ternary expressions. I don’t have Python 3 installed yet, but as far as I know, that “old” way still works to this day, so you can decide for yourself whether or not it’s worth it to conditionally use the new syntax, if you need to support the use of older versions of Python.


回答 10

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

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...

Put the following at the very top of your file:

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)

Then continue on with the normal Python code:

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

回答 11

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

例如:

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

只要您对使用try / except块有足够的专业知识,就可以覆盖大多数基础知识。

I think the best way is to test for functionality rather than versions. In some cases, this is trivial, not so in others.

eg:

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

As long as you’re specific in enough in using the try/except blocks, you can cover most of your bases.


回答 12

在尝试自己解决问题时,我经过快速搜索后才发现此问题,我根据上述一些建议提出了一种混合解决方案。

我喜欢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") )

是的,我知道最后的解码/带状线很可怕,但是我只是想快速获取版本号。我将对此进行完善。

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

I just found this question after a quick search whilst trying to solve the problem myself and I’ve come up with a hybrid based on a few of the suggestions above.

I like DevPlayer’s idea of using a wrapper script, but the downside is that you end up maintaining multiple wrappers for different OSes, so I decided to write the wrapper in python, but use the same basic “grab the version by running the exe” logic and came up with this.

I think it should work for 2.5 and onwards. I’ve tested it on 2.66, 2.7.0 and 3.1.2 on Linux and 2.6.1 on OS X so far.

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

Yes, I know the final decode/strip line is horrible, but I just wanted to quickly grab the version number. I’m going to refine that.

This works well enough for me for now, but if anyone can improve it (or tell me why it’s a terrible idea) that’d be cool too.


回答 13

对于 独立的 python脚本,以下用于强制执行python版本(此处为v2.7.x)的模块docstring技巧适用(在* 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有依赖性。有关背景,请参见此处

For standalone python scripts, the following module docstring trick to enforce a python version (here v2.7.x) works (tested on *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
[...]

This should handle missing python executable as well but has a dependency on grep. See here for background.


回答 14

您可以使用sys.hexversion或进行检查sys.version_info

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

使用以下命令检查Python 3.6或更高版本sys.hexversion

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

使用以下命令检查Python 3.6或更高版本sys.version_info

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,即使它不那么人性化。

希望对您有所帮助!

You can check with sys.hexversion or sys.version_info.

sys.hexversion isn’t very human-friendly because it’s a hexadecimal number. sys.version_info is a tuple, so it’s more human-friendly.

Check for Python 3.6 or newer with sys.hexversion:

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

Check for Python 3.6 or newer with sys.version_info:

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 is more human-friendly, but takes more characters. I would reccomend sys.hexversion, even though it is less human-friendly.

I hope this helped you!


回答 15

我正在扩展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权限位时才有效。

I’m expanding on akhan’s excellent answer, which prints a helpful message before the Python script is even compiled.

If you want to ensure that the script is being run with Python 3.6 or newer, add these two lines to the top of your Python script:

#!/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 # '''

(Note: The second line starts with four single-quotes and ends with three single-quotes. This may look strange, but it is not a typo.)

The advantage of this solution is that code like print(f'Hello, {name}!') won’t cause a SyntaxError if a Python version older than 3.6 is used. You’ll see this helpful message instead:

This script requires Python 3.6 or newer.

Of course, this solution only works on Unix-like shells, and only when the script is invoked directly (such as: ./script.py), and with the proper eXecute permission bits set.


回答 16

这个怎么样:

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

How about this:

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

回答 17

问题很简单。您检查了版本是否小于 2.4,不小于或等于。因此,如果Python版本是2.4,则它不少于2.4。您应该拥有的是:

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

,不

    if sys.version_info < (2, 4):

The problem is quite simple. You checked if the version was less than 2.4, not less than or equal to. So if the Python version is 2.4, it’s not less than 2.4. What you should have had was:

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

, not

    if sys.version_info < (2, 4):