2013-11-14 75 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']

原因與參數的默認值的伎倆工作原理是,它是在函數定義的時間進行評估,而不是

這可以用此片段演示當它被調用時。