2012-10-13 36 views
8

除了爲了正確性而繞過任何實例屬性之外,隱式特殊方法查找通常也會繞過對象的元類的方法__getattribute__()哪些特殊的方法繞過Python中的__getattribute__?

The docs提到的特殊方法,如__hash____repr____len__,而我的經驗還包括__iter__爲Python 2.7知道。

引述an answer to a related question

「魔術__methods__()被特殊處理:它們在內部分配給‘槽’中的數據類型結構,加快他們的查找,他們只能在這些擡頭槽「。

爲了提高我對another question的回答,我需要知道:我們具體討論哪些方法?

+0

哪些方法分配給插槽? –

+7

我認爲列出的每個方法[here](http://docs.python.org/reference/datamodel.html#specialnames)。無論如何,考慮到這隻適用於使用「其語法」調用該方法的情況。例如'a + 5'不會調用'__getattribute__',而'a .__ add __(5)'*會*調用它。 無論何時使用點('.')來訪問屬性,基本上都會調用__getattribute__'。 – Bakuriu

+0

@Bakuriu:非常豐富,謝謝。 – porgarmingduod

回答

4

您可以在python3 documentationobject.__getattribute__,其中規定找到答案:

無條件調用來實現屬性訪問的類的實例。如果這個類還定義了__getattr__(),那麼將不調用後者,除非__getattribute__()顯式地將其稱爲 或引發AttributeError。此方法應返回 (計算)的屬性值或引發AttributeError異常。在 爲了避免這種方法中的無限遞歸,其實現 應該總是調用具有相同名稱的基類方法來訪問它需要的任何屬性,例如對象。 __getattribute__(self, name)

注意

仰視通過語言的語法或內置 功能特殊的方法爲隱式調用的結果時,此方法仍可能被繞過。請參閱特殊方法查找。

this頁面解釋了這個「機械」是如何工作的。基本上,__getattribute__僅在您使用.(點)運算符訪問屬性時(以及Zagorulkin指出的hasattr)纔會調用。

注意,頁面沒有指定哪些特殊的方法都隱含擡頭,所以我認爲,這適用於所有的人(你可能會發現here

+0

你真的檢查過嗎?我沒有檢查2.7.9,看起來這些文檔並不完全正確。 –

1

經過在2.7.9

Couldn 「找不到任何辦法繞過調用__getattribute__,與任何被上objecttype發現的神奇方法:

# Preparation step: did this from the console 
# magics = set(dir(object) + dir(type)) 
# got 38 names, for each of the names, wrote a.<that_name> to a file 
# Ended up with this: 

a.__module__ 
a.__base__ 
#... 

在擱將這個g的那個文件,我把它改名爲一個合適的python模塊(asdf。PY)

global_counter = 0 

class Counter(object): 
    def __getattribute__(self, name): 
     # this will count how many times the method was called 
     global global_counter 
     global_counter += 1 
     return super(Counter, self).__getattribute__(name) 

a = Counter() 
# after this comes the list of 38 attribute accessess 
a.__module__ 
#... 
a.__repr__ 
#... 

print global_counter # you're not gonna like it... it printer 38 

後來我也試圖通過getattrhasattr讓每個這些名稱 - >相同的結果。每次調用__getattribute__

所以,如果任何人有其他的想法...我懶得去看看這個C代碼裏面,但我相信答案在某處。

因此,無論有什麼我沒有得到正確的,或文件說謊。

+1

如果我沒有記錯,我的問題是關於'repr(a)'而不是'a .__ repr __()'。我進入這個領域已經有一段時間了,但是我猜你會得到getattribute版本,因爲你查找屬性,而我們正在討論的內置方法(全局'repr',而不是'__repr__')繞過__repr__'的存在。 – porgarmingduod

+0

重寫'__getattribute__'在每次調用時發出一個print,然後執行:'Counter('a')+ Counter('a')',看看它沒有打印任何東西。因爲它正在繞過標準名稱查找並直接擊中'Counter .__ dict __ ['__ add __']'或者以優化名稱命名這樣一些愚蠢的東西。 – justanr