【问题标题】:Is sys.version_info reliable for Python version checking?sys.version_info 对于 Python 版本检查是否可靠?
【发布时间】:2019-02-20 21:50:13
【问题描述】:

如果我要创建一个模块,我希望在 Python 2 中运行与在 Python 3 中相同的模块,那么有很多选项,包括 sixfutures2to3。如果更改的数量很少,那么这些工具中的每一个都有足够的怪癖,我倾向于只为我的模块实际使用的少数不兼容功能编写一个兼容接口。

实现这一点的合理标准方法是直接进行版本检查。

import module_bar

if sys.version_info >= (3,):
    uniformly_named_foo = module_bar.py3_thing
else:
    uniformly_named_foo = module_bar.py2_thing

是否存在无法正确报告sys.version_info 的奇怪案例?过去,我已经被格式错误的路径、配置、安装、修改等等所困扰,以至于我觉得这不是我应该信任的事情。

当我们开始着手时,我真正关心的是是否实现了特定功能。在 Web 开发中,嗅探用户代理通常被认为是一种不好的做法。相反,人们应该尽最大努力确定某个特定功能是否正在使用中。根据功能的不同,有很多方法可以实现这一点。

if hasattr(module_bar, 'py3_thing'):
    uniformly_named_foo = module_bar.py3_thing
else:
    uniformly_named_foo = module_bar.py2_thing

在我的机器上,第二条路线的速度要慢两倍(并不是说额外的几百纳秒对于一次性操作真的很重要),但它似乎没有任何其他主要缺点。不过有优势吗? 是否存在第二种方法会成功而第一种方法会失败的 Python 安装?

【问题讨论】:

标签: python python-3.x python-2.7


【解决方案1】:
import sys
sys.version_info.major

我认为这是确定一个人使用的是 Python 2.x 还是 Python 3.x 的最佳方式。

【讨论】:

    【解决方案2】:

    是的。 sys.version_info 是确定 Python 版本的可靠方法。

    请参阅 Python 3 documentationPython 2 documentation

    注意:sys.version_info 是可靠的,但不是 sys.version

    系统版本

    一个字符串,其中包含 Python 解释器的版本号以及有关构建号和所用编译器的附加信息。启动交互式解释器时会显示此字符串。 不要从中提取版本信息,而是使用version_infoplatform模块提供的功能。

    如果您担心坏模块会更改 sys.version_info 的值或其他内容,您可以强制重新加载 <module 'sys' (built-in)>

    import sys
    sys.version_info = "boo"
    print(sys.version_info)  # boo
    
    sys.modules.pop("sys")
    import sys  # reloaded
    print(sys.version_info)
    # Output: sys.version_info(major=3, minor=6, ...
    

    【讨论】:

    • “不要从中提取版本信息”警告主要是因为 1)您可能会弄错,2)可以通过更方便、更安全的选项获取信息不需要你解析任何东西。
    • @user2357112 好吧,这就是 Python 文档所说的。
    • @user2357112 我敢打赌,部分原因是他们不承诺次要版本之间的格式兼容性。
    • 像这样使用sys 会导致比您试图解决的理论问题更大的问题。现在你有两个版本的sys 模块,哪个实际上用于任何事情基本上是一个基于初始化顺序的废话。大多数解释器内部将继续使用第一个版本。
    • 造成这种破坏的最明显的灾难性方式之一是sys 的新版本没有sys.modules。或sys.path。或sys.ps1。或sys.stdout。或者一堆其他非常重要的事情。
    【解决方案3】:

    不,sys.version_info不可靠,但仅在某种意义上说 Python 中的几乎所有内容都是可覆盖的,并且因为如果不执行任何伏都教,模块是单例的。考虑以下示例,其中有一个小错字。

    # bad_dependency.py
    import sys
    
    # is_py3 = sys.version_info >= (3,)
    is_py3 = sys.version_info = (3,)
    

    当我们导入这个时会发生什么?嗯……没什么好。

    # our_module.py
    import sys
    import bad_dependency
    
    print(sys.version_info)
    

    当我们运行它时,由于sys 在任何地方都是同一个模块,并且由于我们已经覆盖了我们关心的信息,我们实际上得到了以下行为:

    $ python our_module.py
    (3,)
    

    当然,如果我们的导入有足够糟糕的错误,那么按照这个标准,我们几乎没有任何代码是可靠的。有趣的是,问题不一定是我们的代码引起的,影响当然也不一定是恶意的。

    关于在一些相当标准的 Python 安装(例如 micropython、OSX 等)中是否默认存在此类问题的问题,我仍然不确定答案。

    【讨论】:

    • 查看我为防御bad_dependency而编辑的答案。
    • @iBug 我喜欢这个主意。对于知道sys.version_info 不正确的平台的人,我仍然持保留态度(证明否定很难),但在一两天内,我会选择你的作为最佳答案。
    猜你喜欢
    • 2015-11-15
    • 1970-01-01
    • 2013-10-02
    • 2014-10-08
    • 2010-12-13
    • 2017-05-20
    • 2013-06-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多