将变量注入调用者的范围?

jog*_*ran 15 python variables scope

我可以定义一个函数,在调用时,将新的本地插入到调用者的范围中吗?我有一种感觉,将调用者的locals()传递给函数可能会有效,但有没有办法做我想要的不必这样做?

Pyk*_*ler 18

检查检查模块,由minimock使用它来模拟调用者的范围.

这段代码应该完全符合你的要求:

import inspect
def mess_with_caller():
    stack = inspect.stack()
    try:
        locals_ = stack[1][0].f_locals
    finally:
        del stack
    locals_['my_new_function'] = lambda : 'yaaaaaay'


mess_with_caller()
print my_new_function()
>>> Output: 'yaaaaaay'
Run Code Online (Sandbox Code Playgroud)

  • 这正是我所需要的 django 设置魔法。相当不错。 (2认同)
  • 如果您从顶层模块代码以外的任何其他地方调用`mess_with_caller`,则此操作无效。大概是因为您可以在堆栈框架上修改`f_globals`,但是不能修改f_locals,并且当您从顶级代码`f_locals == f_globals`调用`mess_with_caller`时。换句话说,更适合`mess_with_caller`更改`f_globals`,因为这是它唯一起作用的实例。 (2认同)
  • @ Pykler-他说这在f_locals!= f_globals时不起作用,所以你不妨使用f_globals.请参见http://ideone.com/dbl1lL (2认同)

Ale*_*lli 8

根据Python的规则,你无法改变你的来电者locals; 在当前的实现中,如果你尝试(例如使用黑魔法Anurag建议)你将不会得到异常(虽然我想将错误检查添加到未来的某个版本),但如果你的调用者是,那么它将基本上不起作用一个函数(如果你的调用者是模块顶级代码) - 调用者的实际局部变量实际上不会受到影响.这可以确定调用者locals是明确传入还是通过黑魔法获取:如果您的代码具有任何理智,它们仍然需要被视为只读字典.

相反,您可以让调用者通过一个明确的,真实的,正常的dict(可以根据需要进行初始化locals()),并且您的代码在该dict中所做的所有更改仍将存在于调用者的使用中 - 只是不是"新barenames"当然在调用者的局部范围内,但功能是调用者是否需要使用相同x['foo']x.foo或(如您愿意)刚刚barename foo.

顺便说一下,要使用属性访问语法而不是dict索引语法,你可以这样做:

class Bunch(object): pass

...

# caller code
b = Bunch()
thefun(b)
print b.foo

...

# called function
def thefun(b):
  b.foo = 23
Run Code Online (Sandbox Code Playgroud)

这还包括一个微小的变化,在这种情况下,thefun希望使用dict索引语法(比如它的主体b['foo'] = 23代替b.foo = 23):在这种情况下,调用者只需要使用thefun(vars(b))而不是普通thefun(b),但它可以继续使用b.foo之后的访问语法.