下面的ME可能有点太小了,因为可以用其他方式解决它,但这并不能解决我的真正问题。无论如何,我还是从这个ME入手,因为我觉得这将问题归结为我对Python缺乏了解。
假设我想要一个工厂函数来创建一堆动态函数。我已将问题简化为以下最小示例:
def dynamic_functions(constants):
d = {}
for c in constants:
d[c] = lambda x: c * x
return d
我现在得到以下信息:
>>> fn_2 = dynamic_functions(constants=[2, 3])[2]
>>> fn_2(10) # I would want to get `20`
30
我开始理解这是因为lambda函数中的变量c
不在dict理解期间求值,而是在调用该函数时求值。此时,c
的值为3
,因为这是它在for循环中拥有的最后一个值。 (顺便说一句,如果我将lambda函数转换为命名函数定义,这种情况不会改变。)这种理解得到了这样的事实的支持,即在如下的for循环之后添加del c
:
def dynamic_functions(constants):
d = {}
for c in constants:
d[c] = lambda x: c * x
del c # NB that this line has been added.
return d
提高NameError: free variable 'c' referenced before assignment in enclosing scope
。
如何解决这个问题并创建一个我想要做的工厂,即动态创建具有任意但固定常量的函数?
当然,最小的示例本身可以通过简单地编写一个带有两个参数c
和x
的函数来解决。但是我想解决我了解的范围问题,因为在我的实际用例中,我想基于传递给工厂的参数在分解类上定义属性。因此,我的用例更加复杂,并且无法解决上述ME的问题。 (或者是?我将很高兴学习如何使用。)
这是我真正的问题:
def Structure(params):
properties = {
param_name: property(
fget=lambda self: getattr(self, f"_{param_name}"),
fset=lambda self, value: setattr(self, f"_{param_name}", value)
)
for param_name in params
}
def __init__(self, **kwargs):
for parameter in params:
setattr(self, f"_{parameter}", kwargs.get(parameter))
methods = {
"__init__": __init__
}
_Structure = type(
"some_name", (),
{
**methods,
**properties
}
)
return _Structure
>>> Struct = Structure(params=["x", "y"])
>>> struct = Struct(x=1, y=2)
>>> struct._x
1 # That's correct
>>> struct.x
2 # That is actually the value of struct._y
这仍然是我的问题的简化代码版本,我的实际用例具有更复杂的getter和setter。
如何解决这个问题并创建一个我想要做的工厂,即动态创建具有动态属性的类?