当将新键链接到新的lambda函数时,for循环中的迭代会覆盖以前定义的不同dict键.这是意料之中的事吗



我可能很天真,但我发现以下行为出乎意料。

简介:我需要一个包装器来动态地处理我自己的类,模型的方法。我试图使用dict为动态请求的类的给定数量的成员中的每一个都有一个单独的条目。我迭代地将dict键链接到所选成员,我发现doc字符串被保留了下来,但这些方法会被迭代中的最后一项覆盖,尽管它们的键不同。这里有一个片段,我用numpy代替我自己的类来重现行为。

import numpy as np
name = ["sin","cos"]
bnd = {}
print('Within the defining loop, it works!n')
for nam in name:
# useless indirect function (with doc string)
# equivalent to sin(2*pi*x) 
# or to cos(2*pi*x)
bnd[nam] = lambda x, par: np.__getattribute__(nam)(x*par)
bnd[nam].__doc__ = '"""'+nam+'"""'
print('bnd doc in-loop: {} = {}'.format(nam,bnd[nam].__doc__))
print('bnd method in-loop {}(0,2*pi) = {}'.format(nam,bnd[nam](0,2*np.pi)))
print('n    However after the loop...')
print('bnd keys {}'.format(bnd.keys()))
print('nfirst function doc: {}'.format(bnd["sin"].__doc__))
print('doc is preserved, but instead the method')
print('(should be sin(2 pi *0)) yields {}'.format(bnd["sin"](0,2*np.pi)))
print('nsecond trial_function doc: {}'.format(bnd["cos"].__doc__))
print('doc is preserved, again, and this time the method')
print('(should be cos(2 pi *0)) yields  correctly {}'.format(bnd["cos"](0,2*np.pi)))
print('nSummary: bnd[nam] gets overwritten by the last lambda definition in the loop. nnWhy????') 

如果你运行代码,你会得到以下

Within the defining loop, it works!
bnd doc in-loop: sin = """sin"""
bnd method in-loop sin(0,2*pi) = 0.0
bnd doc in-loop: cos = """cos"""
bnd method in-loop cos(0,2*pi) = 1.0
However after the loop...
bnd keys dict_keys(['sin', 'cos'])
first function doc: """sin"""
doc is preserved, but instead the method
(should be sin(2 pi *0)) yields 1.0
second trial_function doc: """cos"""
doc is preserved, again, and this time the method
(should be cos(2 pi *0)) yields  correctly 1.0
Summary: bnd[nam] gets overwritten by the last lambda definition in the loop. 
Why????

我希望这能澄清我的问题。

正如其他人所解释的。函数中只有一个变量nam。创建lambda时,它不会像创建lambda那样捕获nam的值。相反,所有的lambda共享相同的nam,并且它具有它在函数末尾的任何值。

有几种变通办法。本质上,您需要将nam捕获为一个变量。

";官方的";这样做的方法是,你可以写:

def attribute_getter(nam):
return lambda x, par: np.__getattribute__(nam)(x*par)
bind[nam] = attribute_getter(nam)

快速而肮脏的解决方案是:

bind[nam] = lambda x, par, nam=nam: np.__getattribute__(name)(x * par)

变量nam变为可选的,其被设置为nam的当前值。


编辑:已更改";程序";至";函数";。

最新更新