2012-09-01 17 views
3

我不再推薦舊式的Python類,尤其是在Python 3刪除它們之後。不過,我還是想知道這裏發生了什麼:舊式Python類的神奇方法查找

class MyClass: 
    pass 

my_instance = MyClass() 
str(my_instance) 

這段代碼打印如下:

所以 '< 主要在0x108ec4290> .MyClass實例',我沒有任何明確的繼承,我沒有超載str方法。但是,這並沒有引起所謂的缺失方法的例外。爲什麼?

我知道,老式類有一個「實例」和「類型」和新的樣式類的概念,目的是統一這些概念。那麼Python是否會在實例隱式連接的「實例」類型上找到並調用str方法?

這裏有一些線索:

目錄(my_instance) - 返回:

['__doc__', '__module__'] 

型(my_instance) - 返回:

<type 'instance'> 

目錄(類型(my_instance)) - 返回:

['__abs__', '__add__', '__and__', '__call__', '__class__', '__cmp__', '__coerce__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__div__', '__divmod__', '__doc__', '__eq__', '__float__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__hex__', '__iadd__', '__iand__', '__idiv__', '__ifloordiv__', '__ilshift__', '__imod__', '__imul__', '__index__', '__init__', '__int__', '__invert__', '__ior__', '__ipow__', '__irshift__', '__isub__', '__iter__', '__itruediv__', '__ixor__', '__le__', '__len__', '__long__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__xor__', 'next'] 

任何人都可以準確地解釋舊式類中的類和類型之間的關係以及這裏發生了什麼?

+0

我可能會這樣做,但我如果沒有定義'__str __()',並且'__repr __()'默認爲'__retr __()',那麼'__retr __()'默認爲類似於你所顯示的東西(''if它沒有被覆蓋。 – jedwards

+0

@jedwards:但即使如此,'__repr__'也不在舊式樣實例對象上。所以這將是同樣的魔法......只是一跳。 – jdi

+0

@jedwards是對的。如果是這樣的話,發現缺少__repr__方法有什麼「魔力」? –

回答

1

我相信其他人可以給你更具體的原因,這一點,但有從類似的討論帖位於:old-style class

object是基類,在任何繼承的頂部樹。 堅持基類的目的,我相信是統一 對象的行爲,而不需要太多'魔法'。也就是說,之前 新樣式類,對象就像__doc____str__神奇了性能;現在,他們有他們的原因:因爲他們從基類繼承 他們。

那部分關於「魔法」我相信就是......黑匣子魔法。顯然,舊式類的MRO(方法解析順序)更加神奇,因爲它可能必須檢查instance對象以及type上的顯式定義。無論是這樣,還是舊樣式類的一部分機制總是在找不到的時候提供默認的方法__str__

它現在不那麼神奇的新樣式類,因爲由於繼承,方法是真的在那裏的實例。

這裏是另一個網站與一些好的報價和例子:Principle of Biggest Surprise

對於老式類所有查找在實例來完成。

對於新風格的類的實例,也就是隱含做了所有特殊方法查找在類結構完成

新風格:

class Foo(object): 
    def __str__(self): 
     return "old str" 

foo = Foo() 
foo.__str__ = lambda: "new str" 

print str(foo) 
print foo.__str__() 

# old str 
# new str 

舊式:

class Foo: 
    def __str__(self): 
     return "old str" 

foo = Foo() 
foo.__str__ = lambda: "new str" 

print str(foo) 
print foo.__str__() 

# new str 
# new str 
+0

我不太明白你上面顯示的新樣式代碼片段。 Python隱式調用__str__和str()以及直接調用__str__有什麼區別?因爲你替換了__str__方法,我會認爲這兩個調用都會打印'new str'?這個綁定是在手邊完成的,而對象的__dict__仍然有舊的__str__或什麼的? –

+0

@ durden2.0 - 我更新了報價。它對新樣式類表示,隱式調用對類進行查找。所以str()是隱含的。 – jdi

+0

感謝您的更新。所以所有的隱式查找只查找類對象中可用的方法,而不是類的實例?這個工作到底如何? Python會不知何故地調用類本身的方法進行隱式查找?它似乎仍然需要一個實例,因爲它不是靜態/類方法,對吧? –