2013-11-14 74 views
0

我正在写这样一个类(简化)来表示概率分布。 我想要的只是初始化对象分布只有它的类型和参数,并且它有一些根据它的类型分配的函数。类定义中的类型错误

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) 

现在,当我跑型(dist.pdf)我得到的是一个lambda函数,但是当我运行的功能,说dist.pdf(4.0)一个类型错误:“名单”的对象不是一个调用。

在旁注中,代码的风格/复杂程度如何?

回答

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词典你拥有的方式。例如,对于pdfcdf函数,命名参数不是必需的,但可能对内省有用。另外,您是否可以假设所创建的任何分配正好有两种方法,即pdfcdf,或者该实例是否也有附加方法?

+0

谢谢,我会检查你提到的这些技巧。我只想要一个类,其功能取决于一组参数,事情变得更加复杂,因为我需要的参数取决于'dist_type',这就是为什么我使用字典.. – chuse

-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' 

的代码风格看起来合理,但我犹豫了一下,SETATTR这么多为自我。此外,你的变量名称可能会更具描述性,但也许这是因为你在做数学,而且经常使用数学变量名称:)

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这个迭代过程中的最后一个值是你functions字典,这恰好是一个list"parameters"元素。因为val被lambda捕获,所以稍后当您调用它时,它会尝试呼叫['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']

原因与参数的默认值的伎俩工作原理是,它是在函数定义的时间进行评估,而不是

这可以用此片段演示当它被调用时。