Python 将变量注入调用者';什么范围?

Python 将变量注入调用者';什么范围?,python,variables,scope,Python,Variables,Scope,我是否可以定义一个函数,在调用时将新的局部变量插入调用方的作用域?我觉得将调用者的局部变量()传递到函数中可能会起作用,但是有没有一种方法可以不必这样做就完成我想做的事情呢?根据Python的规则,您不能更改调用者的局部变量;在当前的实现中,如果您尝试(例如,使用Anurag建议的黑魔法),您将不会得到异常(尽管我想在将来的版本中添加错误检查),但如果您的调用者是一个函数(而不是如果您的调用者是模块顶级代码),它基本上是不起作用的--调用方的实际局部变量实际上不会受到影响。这决定了调用方的局部变

我是否可以定义一个函数,在调用时将新的局部变量插入调用方的作用域?我觉得将调用者的局部变量()传递到函数中可能会起作用,但是有没有一种方法可以不必这样做就完成我想做的事情呢?

根据Python的规则,您不能更改调用者的
局部变量
;在当前的实现中,如果您尝试(例如,使用Anurag建议的黑魔法),您将不会得到异常(尽管我想在将来的版本中添加错误检查),但如果您的调用者是一个函数(而不是如果您的调用者是模块顶级代码),它基本上是不起作用的--调用方的实际局部变量实际上不会受到影响。这决定了调用方的
局部变量是显式传入的,还是通过黑魔法获取的:如果您的代码要保持正常,它们仍然需要被视为只读dict

相反,您可以让调用者传入一个显式的、真实的、普通的dict(如果您愿意,可以从
locals()
初始化),并且您的代码在该dict中所做的所有更改仍然会供调用者使用——当然不会作为调用者本地作用域中的“新名称”,但是无论调用方是否需要使用
x['foo']
x.foo
或(如您所愿)只使用裸名
foo
,功能都是相同的

顺便说一句,要使用属性访问语法而不是dict索引语法,可以执行以下操作:

class Bunch(object): pass

...

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

...

# called function
def thefun(b):
  b.foo = 23
这也涵盖了
thefun
希望使用dict索引语法的情况(比如它的主体是
b['foo']=23
而不是
b.foo=23
):在这种情况下,调用方只需要使用
thefun(vars(b))
而不是普通的
thefun(b)
,但是它可以在以后继续使用
b.foo
访问语法。

检查,它被用来模拟调用方的作用域

此代码应该完全满足您的要求:

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'

如果不更改API,这是不可能的,因为CPython在函数调用期间保留对参数列表的引用

一种方法是传递一个对象,并在使用该对象时清除该对象的内部状态

class Obj(object):
    def __init__(self, state):
        self.state = state

def f(o):
    # Do stuff with o.state
    del o.state

假设打电话的人被期望了解被打电话的人和当地人一起进城的风险。听起来像是意大利面条的配方。它被称为“返回”。和往常一样,有一个用例。假设您有一种小型语言,它将表达式与树匹配,并将名称绑定到树节点。我想调用match函数,作为副作用,将这些名称放入调用方的作用域中。这通常是一个糟糕的想法。。。但碰巧我也想这么做,在一个非常特殊的情况下。好吧,听起来好像我真的不可能做我想做的。感谢属性访问的想法;如果我不能使用barenames(x),那么下一个最漂亮的东西可能是属性访问(context.x)。Python是一种完整的动态语言,如果您愿意,您可以覆盖它自己的解释器。我只引用亚历克斯的话是正确的@Pykler的答案只适用于一种特定情况,而不是一般情况。非常感谢,这是一个很好的解决方案!仅供参考:inspect是一个内置的python模块。这正是django设置魔法所需要的。非常好。如果您从顶级模块代码以外的任何地方调用调用调用方
,这将不起作用。这大概是因为您可以在堆栈框架上修改
f_全局变量
,但不能修改f_局部变量,并且当您从顶级代码
f_局部变量==f_全局变量
调用
mess_时。换句话说,
mess\u with_caller
更适合更改
f\u globals
,因为这是它工作的唯一实例。@ferrouswheel编写的代码与调用方的作用域(上一个堆栈)一样简单。你是对的,尽管在某些情况下你可能需要使用f_globals。使用minimock代码作为参考,您将得到您想要的。@Pykler-他是说当f_locals!=f_globals,所以你可以使用f_globals。看见