2014-08-27 140 views
2

Python的類實例對象具有屬性。這些屬性可以是數據屬性或方法。創建Python方法對象

讓我們例如此類

class Foo: 

    def bar(self): 
     print("FooBar") 

並讓創建一個類的實例

fooInstance = Foo() 

正如我已經從文檔讀取和自己測試我意識到 ,每次我在代碼中引用或每次我給我打電話吧

fooInstance.bar 

每次在內部創建一個方法對象。

問題是爲什麼沒有被緩存和重用

一個假設是因爲該方法的對象的可調用對象可以以某種方式改變內部地址(即由於重新分配?)和指針它可以失效。

對不起,如果這個問題是「愚蠢的」,我對Python完全陌生,所以我的知識很少,甚至更少的內部。

回答

2

Python函數是descriptors。您可以通過簡單地看它的dir檢查:

>>> def fn(self): 
...  pass 
... 
>>> dir(fn) 
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name'] 
>>> fn.__get__ 
<method-wrapper '__get__' of function object at 0x7fa5585550c8> 

通知的__get__ method。我們可以用它來生成綁定方法:

>>> class Bar(object): pass 
... 
>>> b = Bar() 
>>> fn.__get__(b, Bar) 
<bound method Bar.fn of <__main__.Bar object at 0x7fa5585cdcd0>> 

其實,這是蟒蛇會自動爲你做,當你在一個類,這是一個函數訪問的屬性。

現在,關於緩存的問題 - 函數可以放在任何地方的類上。我可以像上面那樣向任何類添加綁定方法 - 簡單分配b.fn = fn.__get__(b, Bar),現在實例b具有綁定方法fn,即使Bar的其他實例沒有該方法。我可以爲多個班級做這個。如果描述符要緩存這些值,則需要保留一個查找表,查找實例和類以查看它是否已經爲該實例和類創建了綁定方法。這裏有一個簡單的例子:

def fn(self): 
    return self 

class A(object): 
    fn = fn 

class B(object): 
    fn = fn 

注意AB持有相同的函數的引用 - 並在必要時屬性上的實例訪問他們都會產生綁定方法。

由於self可能不是可破解的,所以查找表首先構建起來會產生問題。我認爲這可能是每次創建新實例的主要原因。 即使不是這種情況,查找表將需要存儲弱引用 - 而不是實際的引用 - 這樣整個事情可以在必要時被垃圾收集。 我猜創建一個新的綁定方法可能與使用weakrefs進行查找和解析時一樣快。

0

你在那裏有一個方法,每次調用它將執行的方法時都沒有參數。方法變量會將該方法分配給其他方法以便稍後調用它。

如果你有一個帶有計數器的變量,並且每次你可以打印出來並且看看它是如何被修改的,你在該方法中增加了一個。