2017-09-14 61 views
2

這是關於蟒2.x的爲什麼這個python類實例可散列?

在下面的類,如果我們子類「對象」,我明白所述方法繼承在派生類Foo包括__hash__(可通過印刷看到這DIR(富())

因此調用哈希(富())調用魔術方法__hash__,使我們的哈希值。

但是,如果我們不繼承「對象「,導致dir(Foo())未列出__hash__方法,那麼爲什麼我們仍然在python2中獲得散列值?

在相信python3因爲從「對象*」類中的方法在默認情況下繼承了這一問題已得到解決。

#class Foo(object) Works since __hash__ is available in the base class 
class Foo: #Why does this work? 
    def __init__(self): 
     self.x = None 
a = Foo() 
print dir(a) # No __hash__ magic method 
print hash(a) 
# Expecting an error like non-hashable or __hash__ not implemented 
# or something similar 
+0

提示:'id(a)'仍然有效。相關:https://stackoverflow.com/questions/17192418/hash-function-in-python –

回答

3

舊式的課程很奇怪。正式的,舊式類的實例並不完全是它們類的實例,它們都是instance類型的實例。 The instance type defines __hash__tp_hash是相當於C定義類型的__hash__的C級插槽),所以儘管它沒有直接在您的實例上定義,也沒有在創建它的類上定義,但它通過奇怪而可怕的魔法在instance類型本身上找到__hash__ (實際上,魔法在於如何使用你的課程特色,因爲它的類型是instance)。

您可以在交互式解釋看到這一點:

>>> class Foo: pass 

>>> Foo().__hash__ # Same basic error for Foo.__hash__ too 
AttributeError       Traceback (most recent call last) 
... 
----> 1 Foo().__hash__ 

AttributeError: Foo instance has no attribute '__hash__' 
>>> type(Foo()) 
<type 'instance'> 
>>> type(Foo()).__hash__ 
<slot wrapper '__hash__' of 'instance' objects> 

即使實例本身不能看到__hash__這樣做是因爲「特殊方法」(即開始和雙下劃線結束這些記錄的特殊方法)被查詢的類型,而不是實例,所以__hash__被發現在instance本身。在C級別,hash(x) is doing the equivalent of type(x).__hash__(x)(它稍微複雜一些,因爲如果__eq__具有自定義定義,但這是總體思路,它將不使用默認的__hash__實現)。

+0

很好的答案!謝謝。 – SeasonalShot