如何优雅地处理由于旧解释器版本导致的失败的未来功能(__future__)导入?

cdl*_*ary 68 python python-import

您如何优雅地处理失败的未来功能导入?如果用户使用Python 2.5运行,并且我的模块中的第一个语句是:

from __future__ import print_function
Run Code Online (Sandbox Code Playgroud)

为Python 2.5编译此模块将失败,并带有:

  File "__init__.py", line 1
    from __future__ import print_function
SyntaxError: future feature print_function is not defined
Run Code Online (Sandbox Code Playgroud)

我想告诉用户他们需要用Python> = 2.6重新运行程序,并且可能提供一些如何操作的说明.但是,引用PEP 236:

在future_statement之前可以出现的唯一行是:

  • 模块docstring(如果有的话).
  • 评论.
  • 空白行.
  • 其他future_statements.

所以我做不了类似的事情:

import __future__

if hasattr(__future__, 'print_function'):
    from __future__ import print_function
else:
    raise ImportError('Python >= 2.6 is required')
Run Code Online (Sandbox Code Playgroud)

因为它产生:

  File "__init__.py", line 4
    from __future__ import print_function
SyntaxError: from __future__ imports must occur at the beginning of the file
Run Code Online (Sandbox Code Playgroud)

来自PEP的这个片段似乎给了内联的希望:

问:我想将future_statements包装在try/except块中,因此我可以使用不同的代码,具体取决于我正在运行的Python版本.为什么我不能?

A:对不起!try/except是一个运行时功能; future_statements主要是编译时的噱头,你的try/except在编译完成后很久就会发生.也就是说,当你尝试使用/ except时,对模块有效的语义已经完成了.由于试/除非将无法完成它看起来 像它应该做到,它只是不允许的.我们还希望保持这些特殊陈述非常容易找到和识别.

请注意,您可以直接导入__future__,并使用其中的信息以及sys.version_info来确定您正在运行的版本与给定功能的状态相关的位置.

想法?

S.L*_*ott 60

"我想告诉用户他们需要用Python> = 2.6重新运行程序,并且可能会提供一些如何操作的说明."

这不是README文件的用途吗?

这是你的选择."包装器":在运行目标aop之前检查环境的一小块Python.

文件:appwrapper.py

import sys
major, minor, micro, releaselevel, serial = sys.version_info
if (major,minor) <= (2,5):
    # provide advice on getting version 2.6 or higher.
    sys.exit(2)
import app
app.main()
Run Code Online (Sandbox Code Playgroud)

什么是"直接进口"的意思.你可以检查一下的内容__future__.你仍然受到a from __future__ import print_function是编译器信息这一事实的束缚,但你可以在导入执行实际工作的模块之前进行调整.

import __future__, sys
if hasattr(__future__, 'print_function'): 
    # Could also check sys.version_info >= __future__. print_function.optional
    import app
    app.main()
else:
    print "instructions for upgrading"
Run Code Online (Sandbox Code Playgroud)

  • 甚至更好,"if(major,minor)<=(2,5)" (19认同)
  • 为什么不"如果sys.version_info [:2] <=(2,5)"更重要的是,我认为,我不喜欢创建仅使用过一次的变量(或者根本不用于"次要"之后的所有内容)例) (10认同)
  • 52 upvotes并没有人指出__future__`中的''print_function'实际上不起作用......应该是`hasattr(__ future__,'print_function')` (3认同)

Sco*_*ths 46

我之前使用的一个相当hacky但很简单的方法是利用Python 2.6中引入字节文字的事实,并在文件的开头附近使用类似的东西:

b'This module needs Python 2.6 or later. Please do xxx.'
Run Code Online (Sandbox Code Playgroud)

这在Python 2.6或更高版本中是无害的,但SyntaxError在任何早期版本中都是无害的.任何试图编译文件的人仍会收到错误,但他们也会得到你想要的任何消息.

你可能认为,因为你必须在你from __future__ import print_function之后拥有这一行,它将是生成它的导入,SyntaxError你不会看到有用的错误消息,但奇怪的是后面的错误优先.我怀疑由于导入的错误本身并不是语法错误,因此在第一次编译过程中不会引发错误,因此首先会引发真正的语法错误(但我猜).

这可能不符合您"优雅"的标准,并且它非常适合Python 2.6,但它可以快速轻松地完成.

  • 优雅!我已经在我的shebang行下使用了这个没有赋值:`b'这个脚本需要Python 2.6,这行是早期版本中的一个SyntaxError',这对于读取异常跟踪和程序员的用户来说是一个非常明确的消息阅读来源. (6认同)

Dav*_*ton 40

只需对其中的相同行发表评论"from __future__ import ...",如下所示:

from __future__ import print_function, division  # We require Python 2.6 or later
Run Code Online (Sandbox Code Playgroud)

由于Python显示包含错误的行,如果您尝试使用Python 2.5运行该模块,您将获得一个很好的描述性错误:

    from __future__ import print_function, division  # We require Python 2.6 or later
SyntaxError: future feature print_function is not defined
Run Code Online (Sandbox Code Playgroud)