请考虑以下代码:
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中的答案不同, 那也很好。
答案 0 :(得分:4)
除了locals()
和globals()
结构之外,编译器还会在嵌套函数中以单元格的形式添加关于“自由变量”的信息,对于任何 local a)未被赋值的变量,b)引用范围变量(Python 3.x添加nonlocal
关键字以允许您分配给这样的变量,就像{{1}一样}关键字)。
在您的具体情况下,没有这样的变量。您的嵌套代码均未引用global
;只有当nonLocalVariable
或anotherFunction
实际使用该变量时,python编译器(因此在字节编译时)添加必要的结构才能从范围中提取LocalClass
。
以下是嵌套设置示例:
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
代码对象列表x
以及co_cellvars
中bar
的代码对象x
列出co_freevars
由于y
从不使用bar
,因此<{1}} 未列出 。对bar
函数的引用具有func_closure
结构,该结构保存x
的当前值,这是bar
创建时范围所给出的值。代码对象保存函数的字节码;它们是在编译时创建的。 func_closure
元组是在运行时根据freevars
和cellvars
结构创建的。
因为这在编译时发生,所以动态创建对这样的范围变量的引用充其量是棘手的。为了您自己的利益,在这种情况下,我甚至不愿意支持使用范围变量。