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

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

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

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

25927 次浏览

我猜你有这样的东西:

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

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

import sys
# check sys.version
import module_foo

Python 不要求导入(除了 from __future__ import [something])位于代码的顶部。

您不应该在脚本本身内部使用任何 Python 2.6特性。另外,在导入任何需要新 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
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 platform
if platform.python_version() not in ('2.6.6'):
raise RuntimeError('Not right version')

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

您可能需要编写 使用 < em > Python 2.x < em > 和 3. x 运行的脚本要求每个 < em > 的最低版本

例如,如果代码使用 Argparse模块,则需要至少2.7(使用2.x Python) 或者至少3.2(使用3.x Python)。

下面的代码片段实现了这样一个检查; 唯一需要适应不同但类似场景的是 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 在比较元组时做正确的事情这一事实:

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

我需要确保我使用的是 Python 3.5(或者更高版本)。我自己胡闹了一会儿,然后我想问问 那么-但是我对答案没有留下深刻的印象(对不起,你们都是 微笑:)。我没有放弃,而是想出了下面的方法。我已经测试了 min_pythonmax_python规范元组的各种组合,它似乎工作得很好:

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

    • 避免用冗余版本检查污染许多模块
    • 如果整个层次结构遵守相同的 Python 版本约束,那么将其放置在包层次结构的顶部将进一步支持 干的主体
    • 利用我可以使用最便携的 Python 代码的地方(文件)(例如 Python1? ? ?)为检查逻辑,仍然写我的 真实模块的代码版本,我想
    • 如果我有其他不兼容“所有 Python 版本”的包 init 内容,我可以将它放到另一个模块中,例如 __init_p3__.py,如示例注释掉的最后一行所示。不要忘记用适当的软件包名称替换 pkgname占位符。
  • 如果你不想要一个最小(或最大) ,只是设置为 = ()

  • 如果你只关心主要版本,那就使用 “一个人”,例如 = (3, ) 不要忘记逗号,否则 ABC1只是一个用括号括起来的(琐碎的)表达式,计算结果为单个 int
  • 您可以指定比一个或两个版本级别(例如 = (3, 4, 1))更好的 min/max
  • 当 max 实际上不大于 min 时,只有一个“考虑以”建议,因为 max 是一个空元组(一个“ none-ple”?)或者元素较少。

注意: 我不太擅长 Windoze 程序员,所以 text_cmd_mintext_cmd_max值是面向 * Nix 系统的。如果您修改了代码以便在其他环境中工作(例如 Windoze 或某个特定的 * Nix 变体) ,请发布。(理想情况下,一个超级智能的代码块就可以满足所有环境的需要,但是我现在只满足于我的 * Nix 解决方案。)

PS: 我对 Python 比较陌生,我没有一个版本小于2.7.9的解释器。0,所以它是 tuff 来测试我的代码是否有早期的变体。另一方面,真的有人在乎吗?(这是我的一个实际问题: 在2.7.9之前,我需要在什么(真实的)上下文中处理解释器的“优雅的错误 Python 版本”问题?)

不,不,不,不,不,不,不,不,不,不,不,不,不

'''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__

从版本9.0.0开始,pip 支撑物 需求-巨蟒字段位于发行版的元数据中,这些元数据可以由 setuptools 从版本 24-2-0开始编写。此功能可通过 python_requires关键字参数到 setup函数。

例子(在 Setup.py中) :

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


)

要利用这个特性,必须先打包项目/脚本(如果还没有完成的话)。这在典型情况下非常容易,但是应该这样做,因为它允许用户轻松地安装、使用和卸载给定的项目/脚本。详情请参阅 Python 打包用户指南

我曾经有一个更复杂的方法来同时支持 Python 2和 Python 3,但是我不再尝试支持 Python 2,所以现在我只使用:

import sys
MIN_PYTHON = (3, 7)
assert sys.version_info >= MIN_PYTHON, f"requires Python {'.'.join([str(n) for n in MIN_PYTHON])} or newer"

如果版本检查失败,您将得到一个类似如下内容的回溯:

AssertionError: requires Python 3.7 or newer

在底部。