如何编写能够正确需要最小化Python版本的Python代码?

我想看看是否有任何方法需要一个最小的Python版本。

由于新的exception处理( as关键字),我有几个需要Python 2.6的Python模块。

它看起来,即使我在我的脚本开始检查python版本,代码将不会运行,因为解释器将在模块内部失败,抛出一个丑陋的系统错误,而不是告诉用户使用一个新的python。

脚本本身不应该使用任何Python 2.6function。 另外,在导入任何需要新Python版本的模块之前,您必须先进行版本检查。

例如像这样开始你的脚本:

 #!/usr/bin/env python import sys if sys.version_info[0] != 2 or sys.version_info[1] < 6: print("This script requires Python version 2.6") sys.exit(1) # rest of script, including real initial imports, here 

我发现最简单的方法(也见这个问题 )只是添加一行:

 b'You need Python 2.6 or later.' 

在文件的开始。 这利用了字节文本在2.6中引入的事实,所以任何早期的版本都会引发一个SyntaxError其中提供的任何消息都是作为堆栈跟踪给出的。

如果你需要Python 2.7,那么:

 {'You need Python 2.7 or later.'} 

这是2.6中的一个语法错误。

对于Python 2.5这应该工作:

 'You need Python 2.5' if 'you want this to run or' else 'this line fails!' 

这是2.4中的一个语法错误。

在比较元组时,您可以利用Python将做正确的事情:

 #!/usr/bin/python import sys MIN_PYTHON = (2, 6) if sys.version_info < MIN_PYTHON: sys.exit("Python %s.%s or later is required.\n" % MIN_PYTHON) 

从版本9.0.0开始,pip 支持分发元数据中的Requires-Python字段,该字段可以由版本24-2-0开始的setuptools编写 。 这个function可以通过python_requires关键字参数来setupfunction。

示例(在setup.py中 ):

 setup( ... python_requires='>=2.5,<2.7', ... ) 

要利用这个function,必须首先打包项目/脚本,如果尚未完成的话。 这在典型情况下非常简单,应该尽可能地完成,因为它允许用户轻松地安装,使用和卸载给定的项目/脚本。 有关详细信息,请参阅Python打包用户指南 。

 import sys if sys.hexversion < 0x02060000: sys.exit("Python 2.6 or newer is required to run this program.") import module_requiring_26 

另外关于这个的很酷的部分是它可以包含在__init__文件或模块中。

我猜你有这样的事情:

 import module_foo ... import sys # check sys.version 

但是module_foo也需要特定的版本? 在这种情况下,重新排列代码是完全有效的:

 import sys # check sys.version import module_foo 

除了from __future__ import [something]之外,Python不要求from __future__ import [something]

而不是索引,你总是可以做到这一点,

 import platform if platform.python_version() not in ('2.6.6'): raise RuntimeError('Not right version') 

为了补充现有的有用的答案:

您可能希望编写使用Python 2.x 3.x运行的脚本 ,并且需要每个 脚本 的最低版本

例如,如果你的代码使用argparse模块,你至less需要2.7(Python 2.x) 3.2(Python 3.x)。

以下代码片段实现了这种检查; 唯一需要适应不同的,但类似的情况是MIN_VERSION_PY2=...MIN_VERSION_PY3=...分配。

如前所述: 在任何其他import语句之前,这应该放在脚本的顶部

 import sys MIN_VERSION_PY2 = (2, 7) # min. 2.x version as major, minor[, micro] tuple MIN_VERSION_PY3 = (3, 2) # min. 3.x version # This is generic code that uses the tuples defined above. if (sys.version_info[0] == 2 and sys.version_info < MIN_VERSION_PY2 or sys.version_info[0] == 3 and sys.version_info < MIN_VERSION_PY3): sys.exit( "ERROR: This script requires Python 2.x >= %s or Python 3.x >= %s;" " you're running %s." % ( '.'.join(map(str, MIN_VERSION_PY2)), '.'.join(map(str, MIN_VERSION_PY3)), '.'.join(map(str, sys.version_info)) ) ) 

如果不满足版本要求,则类似以下消息的内容将打印到stderr,脚本以退出代码1退出。

 This script requires Python 2.x >= 2.7 or Python 3.x >= 3.2; you're running 2.6.2.final.0. 

注意:这是一个早先的,不必要的复杂的答案的大幅改写版本,在感谢Arkady的有用答案之后 ,比较运算符(如>可以直接应用于元组。

我需要确定我正在使用Python 3.5(或者,最终,更高)。 我自己哼了一声,然后我想问这个问题 – 但我没有对答案留下深刻的印象(对不起,你们都::微笑: :)。 我没有放弃,而是提出了下面的方法。 我已经testing了min_pythonmax_python规格元组的各种组合,它似乎很好地工作:

  • 将这段代码放到__init__.py是很有吸引力的:

    • 避免使用冗余版本检查来污染许多模块
    • 将它放置在包层次结构的顶部更加支持DRY主体,假设整个层次结构遵守相同的Python版本约束
    • 利用一个地方(文件),我可以使用最便携的Python代码(例如Python 1 ???)作为检查逻辑,并仍然在我想要的代码版本中写入我的真实模块
    • 如果我有其他不是“所有Python版本”兼容的package-init东西,我可以把它放到另一个模块中,例如__init_p3__.py ,如示例注释掉的最后一行所示。 不要忘记用适当的软件包名称replacepkgname占位符。
  • 如果你不想要一分钟(或最大),只需将其设置为= ()

  • 如果你只关心主要版本,只需使用“one-ple” ,例如= (3, ) 不要忘记逗号,否则(3)只是一个加括号(小数)
  • 您可以指定比一个或两个版本级别更精细的最小/最大值,例如= (3, 4, 1)
  • 当max实际上不大于min时,只有一个“考虑运行”build议,或者是因为max是一个空元组(“非 – ”)?或者元素较less。

注:我不是一个Windoze程序员,所以text_cmd_mintext_cmd_max值是面向* Nix系统。 如果你修复了在其他环境中工作的代码(例如Windoze或某些特定的* Nix变体),请发布。 (理想情况下,一个超智能的代码块就可以满足所有的环境,但是现在我只能使用我的* Nix解决scheme。

PS:我对Python有些新鲜,而且我没有一个版本小于2.7.9.final.0的解释器,所以testing我的代码以获得更早的版本是很困难的。 另一方面,有人真的在乎吗? (这是我的一个真正的问题: 在2.7.9之前,我需要在什么(真正的)语境中处理“优雅的错误 – Python版本”问题?

__init__.py

 '''Verify the Python Interpreter version is in range required by this package''' min_python = (3, 5) max_python = (3, ) import sys if (sys.version_info[:len(min_python)] < min_python) or (sys.version_info[:len(max_python)] > max_python): text_have = '.'.join("%s" % n for n in sys.version_info) text_min = '.'.join("%d" % n for n in min_python) if min_python else None text_max = '.'.join("%d" % n for n in max_python) if max_python else None text_cmd_min = 'python' + text_min + ' ' + " ".join("'%s'" % a for a in sys.argv) if min_python else None text_cmd_max = 'python' + text_max + ' ' + " ".join("'%s'" % a for a in sys.argv) if max_python > min_python else None sys.stderr.write("Using Python version: " + text_have + "\n") if min_python: sys.stderr.write(" - Min required: " + text_min + "\n") if max_python: sys.stderr.write(" - Max allowed : " + text_max + "\n") sys.stderr.write("\n") sys.stderr.write("Consider running as:\n\n") if text_cmd_min: sys.stderr.write(text_cmd_min + "\n") if text_cmd_max: sys.stderr.write(text_cmd_max + "\n") sys.stderr.write("\n") sys.exit(9) # import pkgname.__init_p3__