编程语言
首页 > 编程语言> > python – 仅在给定堆栈帧对象的情况下解析变量名称

python – 仅在给定堆栈帧对象的情况下解析变量名称

作者:互联网

我试图找出是否可以解决堆栈帧中的变量(由inspect.currentframe()返回).

换句话说,我正在寻找一个功能

def resolve_variable(variable_name, frame_object):
    return value_of_that_variable_in_that_stackframe

例如,请考虑以下代码:

global_var = 'global'

def foo():
    closure_var = 'closure'

    def bar(param):
        local_var = 'local'

        frame = inspect.currentframe()
        assert resolve_variable('local_var', frame) == local_var
        assert resolve_variable('param', frame) == param
        assert resolve_variable('closure_var', frame) == closure_var
        assert resolve_variable('global_var', frame) == global_var

    bar('parameter')

foo()

通过框架对象的f_locals和f_globals属性可以轻松查找局部变量和全局变量:

def resolve_variable(variable_name, frame_object):
    try:
        return frame_object.f_locals[variable_name]
    except KeyError:
        try:
            return frame_object.f_globals[variable_name]
        except KeyError:
            raise NameError(varname) from None

但问题是关闭变量.据我所知,它们不存储在像本地和全局变量这样的字典中.更糟糕的是,如果函数实际访问它们,变量只会成为闭包变量(例如,通过读取它的值,如_ = closure_var或使用非局部的closure_var写入; closure_var = _).所以实际上有3种不同的情况:

global_var = 'global'

def foo():
    unused_cvar = 'unused'  # actually not a closure variable at all
    readonly_cvar = 'closure'
    nonlocal_cvar = 'nonlocal'

    def bar(param):
        nonlocal nonlocal_cvar

        local_var = 'local'
        _ = readonly_cvar
        nonlocal_cvar = 'nonlocal'

        frame = inspect.currentframe()
        assert resolve_variable('local_var', frame) == local_var
        assert resolve_variable('param', frame) == param
        assert resolve_variable('unused_cvar', frame) == 'unused'
        assert resolve_variable('readonly_cvar', frame) == readonly_cvar
        assert resolve_variable('nonlocal_cvar', frame) == nonlocal_cvar
        assert resolve_variable('global_var', frame) == global_var

    bar('parameter')

foo()

如何重写我的resolve_variable函数来支持所有这些?它甚至可能吗?

解决方法:

通常不可能. Python只保留闭包实际引用的闭包变量.

>>> import inspect
>>> class Demo(object):
...     def __del__(self):
...         print("Too late, it's gone.")
... 
>>> def f():
...     a = Demo()
...     def g():
...         return inspect.currentframe()
...     return g
... 
>>> frame = f()()
Too late, it's gone.

从这个例子中可以看出,没有希望从框架框架中检查a.没了.

至于闭包变量实际使用的帧,通常显示在f_locals中.我知道一个奇怪的情况,他们不会,如果框架是一个带有闭包变量的类语句:

>>> def f():
...     a = 1
...     class Foo(object):
...         print(a)
...         print(inspect.currentframe().f_locals)
...     return Foo
... 
>>> f()
1
{'__module__': '__main__', '__qualname__': 'f.<locals>.Foo'}
<class '__main__.f.<locals>.Foo'>

在深入了解CPython实现(特别是框架对象,LOAD_CLASSDEREF操作码和inspect.getclosurevars)之后,我认为访问类框架闭包变量的唯一方法是使用ctypes,gc.get_referents或类似的讨厌方法.

另请注意,如果闭包变量值自访问以来已更改,则f_locals dict可能不是最新的;再次访问frame.f_locals refreshes the contents,但是当你看时它可能会再次过时.

标签:python,python-3-x,cpython,stackframe
来源: https://codeday.me/bug/20190607/1194880.html