为什么在Python中修改父框架仅适用于模块框架?

mal*_*ree 4 python python-2.7

我在玩弄inspect.stack().我尝试修改父框架的局部变量,它似乎仅在父框架是模块级别时才起作用.以下代码显示了这一点(Python 2.7):

import inspect


def outer():
    a = 10 
    print a
    modify()
    print a


def modify():
    inspect.stack()[1][0].f_locals['a'] = 8888

outer()

a = 20 
print a
modify()
print a
Run Code Online (Sandbox Code Playgroud)

当父框架是一个函数时,为什么它不起作用?我可以让它运作吗?

Bak*_*riu 6

f_locals的模块堆栈框架globals()!您可以通过在函数内打印is比较来验证这一点:globals()modify

def modify():
    print(inspect.stack()[1][0].f_locals is globals())
    inspect.stack()[1][0].f_locals['a'] = 8888
Run Code Online (Sandbox Code Playgroud)

通过此更改,输出为:

$python3 modify.py 
10
False
10
20
True
8888
Run Code Online (Sandbox Code Playgroud)

修改返回的字典globals() 确实有效(请参阅问题).它明确地 记载该模块实现了自己的一个简单的命名空间dict:

模块由import语句导入(请参阅import语句一节).模块对象具有由字典对象实现的名称空间(这是由func_globals模块中定义的函数的属性引用的字典 ).

但是返回的字典locals()没有必须是本地的命名空间:

注意不应修改此词典的内容; 更改可能不会影响解释器使用的本地和自由变量的值.

某些版本的python2修改locals()工作时使用exec函数内部的语句.尝试添加函数exec ''内部outer并查看输出是否更改(不保证更改!但更有可能).

编辑:在python 2.7.6上,如果堆栈帧使用该exec语句并且代码中没有对局部变量的赋值,我可以使它工作.例如,outer定义为:

def outer():
    exec('a = 10')
    print(a)
    modify()
    print(a)
    locals()['a'] = 9999
    print(a)
Run Code Online (Sandbox Code Playgroud)

我得到输出:

$python2 modify.py 
10
False
8888
9999
20
True
8888
Run Code Online (Sandbox Code Playgroud)

但如果我在以下a = 10后添加exec:

def outer():
    exec('a = 10')
    a = 10
    print(a)
    modify()
    print(a)
    locals()['a'] = 9999
    print(a)
Run Code Online (Sandbox Code Playgroud)

结果是:

$python2 modify.py 
10
False
10
10
20
True
8888
Run Code Online (Sandbox Code Playgroud)

我希望这能告诉你,分配给当地人工作的条件很少,绝对不可靠.

据我所知在python3返回的字典locals()永远只是一个真正的命名空间的副本,因此修改它永远不会奏效.但是也不能保证.

在返回的值f_locals属性仅仅是通过返回的值locals(),在这一点上.

总结:,没有可靠的方法来修改通用堆栈帧的本地命名空间.您不能修改,删除或添加新的局部变量到通用堆栈框架的命名空间.