1

考虑以下代码:

GLOBAL_VARIABLE = 1

def someFunction():
    nonLocalVariable = 2

    def anotherFunction():
        localVariable = 3

        class LocalClass(object):
            __metaclass__ = MyMetaClass
            __customCode = """
                    GLOBAL_VARIABLE + nonLocalVariable + localVariable
                """

    anotherFunction()

someFunction()

我是 的实现者MyMetaClass,这是一个基于__customCode属性内容为类生成方法的元类。__customCode 可以包含 Python 表达式,所以我想确保在中提到的变量名__customCode指的是与在普通 Python 方法中定义的相同变量名相同的对象。

当元类被调用时,它会收到一个包含类内容的字典,这意味着它知道关于__customCode,但这并没有多大帮助。如果您使用inspect.currentframe(1),您将获得语句正在执行的堆栈帧,class 也就是说anotherFunction()。该堆栈框架具有一个.f_locals属性(包含localVariable)和一个.f_globals 属性(包含GLOBAL_VARIABLE,除其他外),但这两者并不能说明整个故事。

给定的堆栈框架anotherFunction()(或我可以从 的实现中获取的任何其他内容MyMetaClass),我如何才能发现所在的名称空间nonLocalVariable以及嵌套在全局和本地名称空间之间的任何其他名称空间?

我目前正在使用 Python 2.7,但如果 Python 3.x 中的答案不同,那也很高兴知道。

4

1 回答 1

4

除了locals()andglobals()结构外,编译器以单元格的形式添加关于“自由变量”的信息,这些单元格指向嵌套函数中的局部变量,对于任何局部变量 a) 没有被分配,并且 b) 引用范围变量(Python 3.x 添加了nonlocal关键字以允许您也分配给这样的变量,就像使用global关键字一样)。

在您的具体情况下,没有这样的变量。您的嵌套代码都没有引用nonLocalVariable; 只有当anotherFunctionLocalClass实际使用该变量时,python 编译器(因此在字节编译时)才会添加必要的结构以便能够nonLocalVariable从范围中拉出。

这是一个示例嵌套设置:

>>> def foo(x):
...     y = None
...     def bar():
...         return x
...     return bar
... 
>>> bar = foo('spam')
>>> foo.__code__.co_cellvars
('x',)
>>> bar.__code__.co_freevars
('x',)
>>> dir(bar.func_closure[0])
['__class__', '__cmp__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'cell_contents']
>>> bar.func_closure[0].cell_contents
'spam'

请注意代码对象如何在foo列表xco_cellvars列出,并且代码对象barxco_freevars; y两者都没有列出,因为bar从不使用它。对函数的引用bar具有一个func_closure结构,该结构保存创建时由作用域给出的当前值。代码对象保存函数的字节码;它们是在编译时创建的。元组是在运行时基于和结构创建的。xbarfunc_closurefreevarscellvars

因为这发生在编译时,所以动态创建对这种作用域变量的引用充其量是棘手的。在这种情况下,为了您自己的利益,我什至不会费心支持使用作用域变量。

于 2013-01-04T13:47:00.657 回答