2011-11-30 56 views
9

我只注意到你可以在Python中做到這一點:Python中的無類方法對任何事都有用嗎?

def f(self): 
    print self.name 

class A: 
    z=f 
    name="A" 

class B: 
    z=f 
    name = "B" 

...

print a.z() 

>>> A 

換句話說,f()行爲就像未在任何類中定義的方法,但可以連接到一。當然,如果它想要附加到的對象上的方法或字段不存在,它會產生一個運行時錯誤。

我的問題:這有用嗎?它有用嗎?有沒有解決問題的情況?也許這是一種定義界面的方式?

回答

6

閱讀細節是的,這是非常有用的,它確實可以一個目的,但也很少有必要這樣做。如果你認爲你需要在定義好補丁程序之後進行補丁,你應該停下來考慮它是否是最好的方法。

一種情況是猴子修補。我在一個龐大的Plone系統中完成了這項工作,其中一些方法需要稍微調整,但是沒有任何簡單的方法可以正常重寫這些行爲。在這種情況下,您有一個複雜的庫,它提供了一種簡單的方法來注入新的或修改的行爲,而無需更改原始庫。

想到的另一種情況是當你想要很多可以自動生成的方法時。例如數據驅動的測試。

def createTest(testcase, somedata, index): 
    def test(self): 
     "Do something with somedata and assert a result" 
    test_name = "test_%d" % index 
    setattr(testcase, test_name, test) 

for index, somedata in enumerate(somebigtable): 
    createTest(MyTestCase, somedata, index) 

時MyTestCase的是你unittest.TestCase生成可以有一個試驗,通過所有的數據流入,但它停止在第一次失敗,你不是要揣摩其中的數據線失敗。通過動態創建方法,所有測試都單獨運行,並且測試名稱告訴您哪一個失敗(上述代碼的原始實際構建的涉及某些數據和索引的更有意義的名稱)。

你不能在類的主體內部這樣做,因爲在定義完成之前,沒有辦法引用類本身或其字典。然而,你可以做一些類似於元類的東西,因爲它可以在創建類本身之前修改類的字典,有時候這也是做類似事情的一種更簡潔的方式。

另一件要注意的是,有些情況下,這將無法正常工作。某些__xxx__特殊方法在創建類後不能被覆蓋:原始定義保存在除類別__dict__之外的其他位置,因此稍後進行的任何更改都可能被忽略。另外,如果使用元類,有時候額外的函數將不會得到元類給屬性作爲類定義一部分的任何處理。

+0

有趣!這也暗示了另一個價值觀可能正在推動對其他地方不重要的方法的定義。顯然對於特殊情況。 –

2

有趣的事實:

  1. 功能在Python是一種類型:

    type(f) # prints <type: function> 
    
  2. 因此,功能是一個可調用的實例,因此它可以在任何地方插入。

  3. 它可用於使功能便攜和模擬即插即用功能。

  4. 這可能是在開發過程中非常方便 - 對於嘗試不同的邏輯(在不同的功能堵漏)

  5. 這提供了抽象邏輯,因爲我們完全可以替代進口功能類的方法。

雖然,我懷疑你將如何使用它來模擬接口!

3

因爲函數對象有__get __(...)方法,所以它是一個非數據描述符。

當你定義在類A的方法,它只是在一個.__ dict__一個函數對象:

In [78]: class A(object): 
    ....:  def f1(self): 
    ....:   pass 
    ....: 

In [79]: A.__dict__["f1"] 
Out[79]: <function f1 at 0x0D39A070> 

但是當你通過屬性得到實例或類此功能,你就會得到綁定的方法或結合的方法。

In [80]: A.f1 
Out[80]: <unbound method A.f1> 

In [81]: A().f1 
Out[81]: <bound method A.f1 of <__main__.A object at 0x0D2F1CD0>> 

這是如何工作的方法。所以,你可以在以後添加方法:

In [82]: A.f2 = lambda self: id(self) 

In [83]: A().f2() 
Out[83]: 221189392 

所以,你的代碼幾乎是一樣的:

class A: 
    def z(self): 
     print self.name 
    name="A" 

請從http://docs.python.org/howto/descriptor.html

+0

是的,但是這個習語有用嗎? –

相關問題