关于Python环境中的局部框架和全局框架的查询

2 投票
1 回答
1782 浏览
提问于 2025-04-18 00:32

从下面的程序来看,我明白了在下面的环境图中,局部框架(方形的蓝色框)属于call()方法的局部激活记录,这个方法是一个'function'类的对象。当我们定义函数square(x)时,这个'function'类的对象是在内部创建的。

enter image description here

我的问题是:

如果我上面的理解是正确的,那么全局框架属于哪个类的对象的方法呢?

因为我觉得,控制权是从某个对象(特定类类型)的某个方法传递到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。这意味着:

  1. co_names 中找到索引为 0 的名字,也就是 'mul'
  2. func_globals 中找到名字 'mul' 并将其加载到栈中
  3. 执行其余的逻辑

撰写回答