3

我有一个功能P()。调用load_variables()应该给P变量xload_variables应该能够接受默认值作为关键字参数。

如何才能做到这一点?

我尝试了以下方法:

import inspect
def P():
    x = 1
    load_variables(x = 2)
    return x

def load_variables(**kargs):
    stack = inspect.stack()
    try:
        locals_ = stack[1][0].f_locals
    finally:
        del stack
    for __k, __v in kargs.iteritems():
        locals_[__k] = __v

print P() # => should print 2

x = 1条线实际上不应该在那里,因为我load_variables()只想放出xintoP的范围。

还有另一种可能更好的方法来做到这一点吗?我想要的是:

  1. 变量有一个默认值,例如x = 2在上面的调用中load_variables()
  2. 我可以覆盖这些load_variables,例如,load_varibales()可以访问变量字典,如果x已经在这里,我们覆盖它,并溢出它x而不是作为默认参数给出的那个。
4

3 回答 3

1

既然我们在这里谈论 Python,可能有办法做到这一点,但我想知道:你应该尝试吗?

通常,最好定义一个共享存储/值对象,然后传递它:

data = {}

def P(data):
     load_variables(data, x=2)
     return data['x']

def load_variables(data, **kargs):
     data.update(kargs)

这样,您就不会产生不可预见的副作用。

于 2012-08-06T10:01:56.410 回答
1

更新:正如 DSM 指出的,locals()不支持更新。所以,答案是不正确的,至少对于 CPython 是这样。

你可以load_variables()返回一个字典并使用它locals()来更新局部变量:

def P():
    x=1
    locals().update(load_variables(x=2))
    return x

def load_variables(**kargs):
    res={}
    for __k, __v in kargs.iteritems():
        res[__k] = __v
    return res

请注意,这x=1是必需的,否则x将被字节码编译器假定为全局变量,您将获得NameError异常return x

如果你真的想摆脱x=1你可以我们retrun locals()['x']代替。

于 2012-08-06T09:12:17.847 回答
1

Python 编译器和字节码解释器在可能的情况下处理对局部变量的引用,作为定义大小数组的槽。这意味着如果局部变量没有在作用域中初始化(分配给),那么语言将不知道该变量的插槽存在于该作用域中,而是会在封闭作用域或全局作用域中查找该变量。查看函数的反汇编P

def P():
    load_variables(x=2)
    return x

dis.dis(P)
  2           0 LOAD_GLOBAL              0 (load_variables)
              3 LOAD_CONST               1 ('x')
              6 LOAD_CONST               2 (2)
              9 CALL_FUNCTION          256
             12 POP_TOP             

  3          13 LOAD_GLOBAL              1 (x)
             16 RETURN_VALUE        

您可以看到,如果没有x在本地范围内分配 to ,P则会在全局范围内查找它。

正确的方法是load_variables使用解包显式声明您希望函数返回哪些变量:

x, y, z = load_variables(...)
于 2012-08-06T09:18:29.827 回答