在Python中读取父级作用域

24 浏览
0 Comments

在Python中读取父级作用域

假设我有一个函数的层次结构,我希望能够访问(而不是更改!)父级的作用域。下面是一个例子。

假设我有一个函数的层次结构,我希望能够访问(而不是更改!)父级的作用域。这是一个说明性的例子。

def f():

a = 2

b = 1

def g():

b = 2

c = 1

print globals() # 包含 a=1 和 d=4

print locals() # 包含 b=2 和 c=1,但没有 a

print dict(globals(), **locals()) # 包含 a=1, d=4(来自全局变量),b=2 和 c=1(来自 g)

# 我希望 a=2 和 b=1(来自 f),d=4(来自全局变量),没有 c

g()

a = 1

d = 4

f()

我能够从 g 函数中访问 f 函数的作用域吗?

0
0 Comments

在Python中,通常情况下你是无法读取父作用域的。如果你的Python实现支持堆栈帧(CPython支持),你可以使用inspect模块检查调用函数的帧,并提取局部变量,但我怀疑这不是解决你想解决的问题的最佳方法(无论那个问题是什么)。如果你认为你需要这样做,那么你的设计可能存在一些缺陷。

需要注意的是,使用inspect可以让你上溯调用堆栈,而不是上溯词法作用域的堆栈。如果你从f()返回g,那么f的作用域将消失,因此根本没有办法访问它,因为它甚至都不存在。

这是由于安全问题而不能这样做吗?我觉得作用域非常微妙/令人困惑,但是一旦你从f中调用gf的作用域肯定仍然存在,因为之后你又回到f中执行代码!我思考这个问题的原因是为了进行单元测试,测试副作用... :s

不,这不是出于安全原因。正如我所说,如果你的Python实现支持堆栈帧,你是可以上溯调用堆栈的——只需使用inspect.currentframe().f_back.f_locals这样的代码来获取调用帧的局部变量,这个帧将是你示例中的f的一个实例。你无法访问词法作用域的变量是因为这个概念本身就是没有意义的。在调用堆栈中可能存在多个f的实例,它们都有不同的局部变量,或者可能根本没有实例。

你不应该这样做的原因是违背了词法作用域的核心思想,与动态作用域相对立的编程语言(几乎所有编程语言)是不支持动态作用域的。详细信息请参见en.wikipedia.org/wiki/…

我觉得让我感到困惑的是g确实可以访问f的变量(例如:e.g.)...但我们只是无法显示它们。

g()无法访问fb,除非你使用堆栈帧introspection,因为gb将会隐藏fb。一旦你在闭包中引用了f的某些变量,它们就会附加到闭包中,所以你可以通过introspection访问它们。但是你的代码实际上并没有访问f的任何名称,因此它不会生成闭包。

啊哈!这就是我之前没有理解的部分(它们只在被查找后才会附加)。如果我们能够遍历所有“可能”的变量,那就完成了...但是我们不知道它们是什么!如果你在函数f中定义f_local_state = locals().keys(),那么在g中你可以遍历f的作用域,因为你可以在g中访问f_local_state

0