Python 函数,该函数故意将变量泄漏到调用方';s范围
我有一个函数Python 函数,该函数故意将变量泄漏到调用方';s范围,python,variables,scope,metaprogramming,Python,Variables,Scope,Metaprogramming,我有一个函数p()。调用load_variables()应该给出P变量x。 load\u变量应该能够接受默认值作为关键字参数 如何做到这一点 我尝试了以下方法: import inspect def P(): x = 1 load_variables(x = 2) return x def load_variables(**kargs): stack = inspect.stack() try: locals_ = stack[1][0]
p()
。调用load_variables()
应该给出P
变量x
。
load\u变量
应该能够接受默认值作为关键字参数
如何做到这一点
我尝试了以下方法:
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()
将x
放在p
的范围内
有没有其他更好的方法?我想要的是:
load_Variables()
时,x=2
load\u variables
中覆盖这些变量,例如,load\u varibles()
可以访问变量字典,如果x
已经在这里,我们会覆盖它,并溢出这个x
,而不是作为默认参数给出的一个更新:正如DSM在下面指出的,不支持更新
locals()
。所以,答案是不正确的,至少对CPython来说是这样
您能否使load_variables()
返回一个字典,并使用locals()
更新局部变量:
请注意,x=1
是必需的,否则字节码编译器将假定x
为全局变量,您将得到namererror
异常返回x
如果你真的想摆脱
x=1
,你可以让我们重新运行locals()['x']
。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
,p
将在全局范围内查找它
正确的方法是使用解包明确说明您希望load\u variables
函数返回哪些变量:
x, y, z = load_variables(...)
既然我们在这里谈论Python,可能有一种方法可以做到这一点,但我想知道:您应该试试吗 通常,最好定义一个共享存储/值对象,然后将其传递:
data = {}
def P(data):
load_variables(data, x=2)
return data['x']
def load_variables(data, **kargs):
data.update(kargs)
这样,您就不会有不可预见的副作用。不幸的是,这不起作用:您不能以这种方式更新
本地人
口述,因为这样的口述是无效的P
在CPython和PyPy中为我返回1,在IronPython中为我返回2,这取决于实现。我如何保证参数的顺序与返回时的顺序相同?例如,像@Mohammad Ali writes一样返回,print load_变量(x=2,y=4,z=10)
作为{'y':4,x':2,z':10}
@MadsOhmLarsen您必须将它们作为返回x,y,z
返回。关键字参数是一个dict,所以它不应该关心顺序,这就是我得到上面混合返回的原因。有没有可能获取它们输入到加载变量的顺序,这样我就可以以相同的顺序返回未知数量的关键字参数?@madshomlarsen抱歉,没有,**kwargs
参数没有顺序。您必须将参数作为文本加载变量(('x',2),('y',4),('z',10))
。这就是我所担心的。谢谢。+1“流血”进入更高范围的想法似乎有点血腥
data = {}
def P(data):
load_variables(data, x=2)
return data['x']
def load_variables(data, **kargs):
data.update(kargs)