有没有办法在运行时影响本地人?

时间:2009-10-07 21:38:37

标签: python python-3.x locals

我其实想要创建一个新的本地。我知道这听起来很可疑,但我认为我有一个很好的用例。基本上我的问题是,当我尝试打印鸡蛋时,此代码抛出“NameError:全局名称'鸡蛋'未定义”:

def f():
    import inspect
    frame_who_called = inspect.stack()[1][0]
    frame_who_called.f_locals['eggs'] = 123

def g():
    f()
    print(eggs)

g()

我发现了这件旧事: http://mail.python.org/pipermail/python-dev/2005-January/051018.html

这意味着我可以使用ctypes并调用一些秘密函数来完成它,尽管他们只讨论了更新值。但也许有一种更简单的方法?

3 个答案:

答案 0 :(得分:3)

我对你的用例非常好奇。为什么在地球上你试图将一个新的局部戳到调用者的框架中,而不是简单地做这样的事情:

def f():
    return 123

def g():
    eggs = f()
    print(eggs)

毕竟,你可以返回一个包含任意数量值的元组:

def f():
    return 123, 456, 789

def g():
    eggs, ham, bacon = f()
    print(eggs, ham, bacon)

答案 1 :(得分:2)

正如Greg Hewgill在对该问题的评论中提到的那样,我回答another question关于修改Python 3中的locals,我将在这里给出一些回顾。

关于这个问题有一个post on the Python 3 bug list - 它在Python 3手册中有些记载。 Python 3使用一个数组用于本地而不是像Python 2中那样的字典 - 优点是局部变量的查找时间更快(Lua也这样做)。基本上,数组是在“字节码 - 编译时”定义的,不能在运行时修改。

具体参见Georg Brandl's post on the bug list中的最后一段,了解为什么这不能(也可能永远不会)在Python 3中有效的详细信息。

答案 2 :(得分:1)

在Python 2. *中,你可以通过击败本地人的正常优化来获得这样的代码:

>>> def g():
...   exec 'pass'
...   f()
...   print(eggs)

exec语句的存在会导致Python 2以完全非优化的方式编译g,因此本机在dict中而不是像往常一样在数组中。 (性能影响可能相当大)。

这种“去优化”在Python 3中不存在,其中exec不再是一个语句(甚至不是一个关键字,只是一个函数) - 即使在它后面加上括号也无济于事。 ..:

>>> def x():
...   exec('a=23')
...   print(a)
... 
>>> x()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in x
NameError: global name 'a' is not defined
>>> 

即即使exec现在也不能“创建在def时间不知道的本地人”(即,当编译器执行其传递以将函数体转换为字节码时)。

你最好的选择就是放弃。第二好的方法是让你的f函数在调用者globals中注入新名称 - 那些毕竟仍然是一个字典。