【问题标题】:How can Python introspect on which language features are activated?Python 如何自省激活了哪些语言特性?
【发布时间】:2019-01-26 20:31:56
【问题描述】:

在这个 Python 2.7 代码中,应该用什么代替 GET_MY_COMPILER_FLAGS()

from __future__ import print_function

def ReportCompilerFlags():
    myFlags = GET_MY_COMPILER_FLAGS()  # how?
    import __future__
    for featureName in __future__.all_feature_names:
        thisFlag = getattr(__future__, featureName).compiler_flag
        print('File {fileName} has {featureName} turned {status}.'.format(
            fileName = __file__,
            featureName = featureName,
            status = 'ON' if (myFlags & thisFlag) else 'off',
        ))
ReportCompilerFlags()

期望的输出:

File /path/to/this/script.py has nested_scopes turned off.
File /path/to/this/script.py has generators turned off.
File /path/to/this/script.py has division turned off.
File /path/to/this/script.py has absolute_import turned off.
File /path/to/this/script.py has with_statement turned off.
File /path/to/this/script.py has print_function turned ON.
File /path/to/this/script.py has unicode_literals turned off.   

我知道我可以检查 globals() 以查看它是否包含适当命名的符号,而不是查看标志,但显然误报和误报都是可能的。

更新:我更新了标题以从经典的 XY 问题中挖掘出这个问题。要查询语言功能的激活状态,事实证明我应该查看的不仅仅是编译器标志,因为编译器实际上并没有将标志用于已经是强制性的功能。

【问题讨论】:

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


    【解决方案1】:

    您可以检查代码对象的co_flags。这包括所有__future__ 标志和一堆用于其他用途的标志,例如代码对象是否用于生成器。

    import inspect
    
    all_flags = inspect.currentframe().f_code.co_flags
    

    请注意,这会告诉您哪些标志处于活动状态,而不一定是哪些功能处于活动状态。如果您的 Python 版本中默认启用某个功能,则可能不会设置其标志。您可以检查功能对象的getMandatoryRelease 以确定是否默认打开标志:

    import sys
    
    def on_by_default(feature):
        return feature.getMandatoryRelease() <= sys.version_info
    

    另外,请确保您拥有正确的代码对象。例如,如果您将其包装在库函数中,则应确保您没有查看库函数自己的标志:

    import inspect
    import types
    
    def code_flags(target=None):
        """
        Returns code flags for the caller of this function, or for a
        specified code or frame object.
        """
        if target is None:
            target = inspect.currentframe().f_back
        if isinstance(target, types.FrameType):
            target = target.f_code
        return target.co_flags
    

    【讨论】:

    • 谢谢。这对 Python 实现有多具体?例如,它是仅限 CPython 吗? (想想看,我什至不确定我在问题中编写的代码是否仅适用于 CPython...)
    • 注意,如果你把这段代码放到一个单独的函数GET_MY_COMPILER_FLAGS中,那么写inspect.currentframe().f_back.f_code.co_flags会更正确。否则,您将检查定义 GET_MY_COMPILER_FLAGS 的模块的标志,而不是调用的标志。
    • @jez 请参阅currentframe 下的备注:docs.python.org/2/library/inspect.html。如果您打算在没有堆栈的 Python 实现上运行(有吗?),您可以避免使用 inspect 模块,而改写 myFlags = ReportCompilerFlags.f_code.co_flags
    • @jez: Seems to work on PyPy. 我认为代码和框架对象是实现细节,但 PyPy 与 CPython 有足够的相似性,因此它可以工作。
    • 不确定这是否真的是一个新问题,但我的前提可能有问题:此解决方案适用于 Python 2,但当我也在 Python 3 中尝试它时,我收到的答案是各种功能应该自动开启,如 print_functionwith_statement,关闭。这种方法有什么问题吗?
    【解决方案2】:

    根据 user2357112 的回答和其他有用的 cmets,这是我最终编写的库函数:

    import sys
    import inspect
    import __future__
    
    def features(stackBack=0):
        featureStatus = set()
        frame = None
        for featureName in __future__.all_feature_names:
            feature = getattr( __future__, featureName)
            if feature.getMandatoryRelease() <= sys.version_info:
                activated = True
            else:
                if frame is None:
                    frame = inspect.stack()[abs(stackBack) + 1][0]
                activated = (frame.f_code.co_flags & feature.compiler_flag) != 0
            if activated:
                featureStatus.add(featureName)
        return featureStatus
    

    假设我将其保存为language.py。 Python 2.7.12 和 3.6.8 各自的输出是:

    $ python -c 'import language; print(language.features())'
    set(['with_statement', 'generators', 'nested_scopes'])
    
    $ python3 -c 'import language; print(language.features())'
    {'unicode_literals', 'with_statement', 'print_function', 'absolute_import', 'generators', 'division', 'nested_scopes'}
    

    一个典型的用例可能是测试'unicode_literals' in features() 来检查您当前是否有该特定功能处于活动状态,或者'unicode_literals' in features(stackBack=1) 来检查它在调用您的任何模块中是否处于活动状态。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-09
      • 2012-01-11
      • 2011-12-21
      • 2011-07-17
      • 1970-01-01
      • 1970-01-01
      • 2011-04-04
      • 2011-02-19
      相关资源
      最近更新 更多