我正在编写一个这样的类(简化)来表示概率分布。 我想要的是仅使用其类型和参数初始化对象Distribution,并且根据其类型分配一些函数。
functions = {'exp':{
'parameters': ['l'],
'pdf': lambda x,p: exp(x/p[0])*p[0],
'cdf': lambda x,p: 1-exp(x/p[0]) },
'uniform':{
'parameters': ['x1','x2'],
'pdf': lambda x,p: 1/(p[1]-p[0]),
'cdf': lambda x,p: (x-p[0])/(p[1]-p[0]) }
}
class Distribution:
def __init__(self,dist_type,**parameters):
self.dist_type = dist_type
self.parameters = parameters
self.p = [ self.parameters[z] for z in functions[dist_type]['parameters'] ]
for key,val in functions[dist_type].items():
if key == 'parameters':
pass
else
setattr(self, key, lambda x:val(x,self.p))
dist = Distribution('exp',l=3.5)
现在,当我运行type(dist.pdf)时,我得到的是一个lambda函数,但是当我运行该函数时,比如dist.pdf(4.0),一个TypeError:'list'对象不是可调用的。
另一方面,代码的样式/复杂程度如何?
答案 0 :(得分:2)
你是关闭的受害者。这是一个可能的解决方案:
for key,val in functions[dist_type].items():
if key == 'parameters':
pass
else:
def f(x, dist=val):
return dist(x, self.p)
setattr(self, key, f)
偶然地,此迭代期间val
的最后一个值是"parameters"
dict的functions
元素,恰好是list
。由于lambda会捕获val
,因此稍后当您调用它时,它会尝试调用['l'](4.5, 3.5)
- ['l']
作为"parameters"
项的值。
这可以通过以下代码段来演示:
class Distribution:
def __init__(self,dist_type,**parameters):
self.dist_type = dist_type
self.parameters = parameters
self.p = [self.parameters[z] for z in functions[dist_type]['parameters']]
for key,val in functions[dist_type].items():
if key == 'parameters':
pass
else:
setattr(self, key, lambda x: val)
dist = Distribution('exp',l=3.5)
print dist.pdf(4.0)
输出:
[ 'L']
参数默认值的技巧起作用的原因是它在函数定义时被评估,而不是在被调用时被评估。
答案 1 :(得分:1)
你被Python中的范围问题所困扰。在这一行:
setattr(self, key, lambda x:val(x,self.p))
val
只是在lambda
最终调用时查找的名称,而不是在定义lambda
时引用的对象。一种解决方法是添加第二个参数,其默认值 在定义时绑定:
for key,val in functions[dist_type].items():
if key == 'parameters':
pass
else:
setattr(self, key, lambda x,val=val: val(x,self.p))
我不知道我会尝试在您正在尝试的字典中嵌入子类定义。有几种技术可用(类工厂,元类),它们可以生成类似
的类exp_dist = make_distribution('exp')
d = exp_dist(l=3.5)
d.pdf(4.0)
此类解决方案的复杂性取决于您的使用案例,以及您选择以您的方式构建functions
字典的原因。例如,pdf
和cdf
函数不需要命名参数,但可能对内省有用。另外,您是否可以假设创建的任何分发都有两种方法pdf
和cdf
,或者实例也可以使用其他方法?
答案 2 :(得分:-3)
当我尝试运行dist.pdf()时,我得到:
Traceback (most recent call last):
File "./dist-pdf", line 30, in <module>
dist.pdf()
TypeError: <lambda>() missing 1 required positional argument: 'x'
代码风格看起来很合理,虽然我犹豫了一下,但仍然犹豫不决。此外,您的变量名称可能更具描述性,但可能是因为您正在进行数学运算,并且数学通常使用较差的变量名称:)