关于Python环境中的局部框架和全局框架的查询
从下面的程序来看,我明白了在下面的环境图中,局部框架(方形的蓝色框)属于call()方法的局部激活记录,这个方法是一个'function'类的对象。当我们定义函数square(x)时,这个'function'类的对象是在内部创建的。
我的问题是:
如果我上面的理解是正确的,那么全局框架属于哪个类的对象的方法呢?
因为我觉得,控制权是从某个对象(特定类类型)的某个方法传递到square.call(3)方法的。
1 个回答
2
当你定义一个函数时,它会被赋予一个只读属性,叫做 func_globals
(在2.6版本后也叫 __globals__
,而在3.0版本后只用这个名字)。这个属性对应的是当前模块的命名空间,就像是对 module.__dict__
的一个视图。你可以试试,比如:
>>> square.func_globals
# get a big dictionary-like object here
每当这个函数访问一个全局变量时,都会查询这个对象。当你在其他模块中导入这个函数时,它仍然会保留对原始作用域的引用,并从那里获取全局变量。换句话说,以下代码:
def square(x):
return mul(x, x)
大致上和下面的代码是一样的:
def square(x):
return globals()['mul'](x, x)
或者
def square(x):
return square.func_globals['mul'](x, x)
所以,总结一句话:函数的全局变量属于它被定义的模块,并通过函数对象的属性来访问。
更新
下面是更详细的解释(适用于CPython)。理解Python最重要的一点是,与C等语言不同,它没有“声明”和“执行”之间的明确分隔。当你加载一个模块时,它的代码会被直接执行。当解释器遇到一个函数定义时,它会创建一个函数对象并将其赋值给变量。模块中定义或导入的任何内容都会作为全局变量对这个函数可用。让我们看看这个函数对象:
>>> import dis
>>> dis.dis(square.func_code) # disassemble the function's bytecode
2 0 LOAD_GLOBAL 0 (mul)
3 LOAD_FAST 0 (x)
6 LOAD_FAST 0 (x)
9 CALL_FUNCTION 2
12 RETURN_VALUE
>>> square.func_code.co_names
('mul',)
你可以看到在开头有代码 LOAD_GLOBAL 0
。这意味着:
- 在
co_names
中找到索引为0
的名字,也就是'mul'
- 在
func_globals
中找到名字'mul'
并将其加载到栈中 - 执行其余的逻辑