如何修改其他作用域的变量?

1 投票
2 回答
983 浏览
提问于 2025-04-16 08:32

目前,我正在尝试以下方法:某个 mutator 函数使用 locals() 来接受其他函数的局部作用域。

def mutator(locals):
    locals['n'] = 10
    locals['l'].append(10)

def f():
    n = 1
    l = [1]
    mutator(locals())
    print(n,l) # >>> 1, [1,10]

f(None)

这个方法按预期工作:我能够修改可变列表的内容,但无法将另一个不可变的 int 重新绑定到同一个名字。

现在,我看到了一些选择:

  • eval()exec() 等等
  • mutator() 中玩弄栈帧和局部变量
  • 把这些变量放在一个 dict 中:虽然不太方便,但可能是最好的选择

限制条件是:目标函数 f() 只能包含一个函数调用,可能带有参数,并且那个函数应该能够改变 f() 当前作用域中的值。

那么……有没有办法在运行时重新引入变量的值(绑定另一个对象)呢?我不相信没有好的技巧可以实现这一点!


这是我想要实现的一个例子:

def view(request): # Yes, that's Django!
    q = MyModel.objects.all()

    data = { 'some_action': True, 'items_per_page': 50 } # defaults. Mutators can change this
    mutators.launch(locals(), data ) # Launch mutators that may want to narrow the QuerySet

    if data['some_action']: # do something useful if no mutator has disabled it
          ...

    # paginate using data['items_per_page']

我不想在这里使用 data 字典:能够将它们作为局部变量修改会更好看,也更方便。请注意,q 的 QuerySet 对象是可变的,变更函数可以改变它的内容。

2 个回答

0

这样做:

def mutator(l):
    l.append(10)
    return 10

def f():
    n = 1
    l = [1]
    n = mutator(l)
    print(n,l) # >>> 1, [1,10]

f()

我知道这不是你想要的聪明方法,但它确实有效。:-)

如果你想要一组可以全局使用的配置选项,可以随意开启和调整,就把它们放在一个对象里:

class Settings(object):
    def __init__(self):
         self.n = 1
         self.l = [1]

现在你可以随心所欲地修改这些变量了。

3
class AttributeCollection(object):
    pass
shared_settings= AttributeCollection()
# now improvise
shared_settings.temperature= 30
shared_settings.samples= []
# etc

把那个 shared_settings 传来传去,或者让它变成全局的,然后把它的属性设置成你想要的样子。

你看,函数里的 locals() 就是一个命名空间,专门用来在这个函数内部操作的(而且是为了这个目的进行了优化)。所以,使用另一个命名空间(我建议用 shared_settings 对象)作为你代码的公共区域。

撰写回答