2015-11-25 55 views
12

如果我們有x = type(a)x == y,是否暗示x is yclassobjects是單身人士嗎?

這裏是一個反例,但它是一個騙子:

>>> class BrokenEq(type): 
...  def __eq__(cls, other): 
...   return True 
...  
>>> class A(metaclass=BrokenEq): 
...  pass 
... 
>>> a = A() 
>>> x = type(a) 
>>> x == A, x is A 
(True, True) 
>>> x == BrokenEq, x is BrokenEq 
(True, False) 

我不能創建這樣一個反例:

>>> A1 = type('A',(), {}) 
>>> A2 = type('A',(), {}) 
>>> a = A1() 
>>> x = type(a) 
>>> x == A1, x is A1 
(True, True) 
>>> x == A2, x is A2 
(False, False) 

爲了澄清我的問題 - 不覆蓋平等運營商做些瘋狂的事情,一個班級是否有可能存在兩個不同的存儲位置,或者導入系統是否可以防止這種情況?

如果是這樣,我們該如何證明這種行爲 - 例如,用reload__import__做奇怪的事情?

如果不是,那是由語言保證或記錄在任何地方?


尾聲

# thing.py 
class A: 
    pass 

最後,這是澄清真實的行爲,我(和它的支持在Blckknght答案索賠)

>>> import sys 
>>> from thing import A 
>>> a = A() 
>>> isinstance(a, A), type(a) == A, type(a) is A 
(True, True, True) 
>>> del sys.modules['thing'] 
>>> from thing import A 
>>> isinstance(a, A), type(a) == A, type(a) is A 
(False, False, False) 

所以,儘管代碼使用importlib.reload的用戶可能會按類標識中斷類型檢查,無論如何也會中斷isinstance

+1

有趣的問題!我認爲他們必須這樣做,只是因爲任何給定類型的對象大概只能以一種一致的方式創建。我能否引用某些說法?還沒。 –

+0

因爲python中的所有東西都是對象,所以類是它們元類的「正義」實例 - 爲什麼我們不能擁有「相同」類的其他實例?然而,我沒有找到一個例子,其中導入一個類或以其他方式將一個名稱綁定到該類不只是獲得對同一對象的另一個引用。 – wim

+0

也許這只是在給定實現中碰巧是真實的那些事情之一,但在語言規範中沒有解決,並且不能保證。 –

回答

5

不,沒有辦法創建兩個比較相等而不相同的類對象,除非通過元類__eq__方法搞亂。

這種行爲雖然不是類獨特的東西。這是沒有在其類中定義的__eq__方法的任何對象的默認行爲。該行爲從object繼承,這是所有其他(新樣式)類的基類。對於具有相同語義的內建類型(例如,比較其內容的容器類型)和定義自己的__eq__運算符的自定義類,它只是被覆蓋。

至於在不同的內存位置獲取兩個不同的引用到相同的類,由於Python的對象語義,這是不可能的。對象的內存位置是其標識(至少在cpython中)。另一個具有相同內容的課程可以存在於其他地方,但就像在您的A1A2示例中,它將被所有Python邏輯視爲不同的對象。

+0

嗨!所以答案似乎是:不,他們不是單身人士(這意味着必須攔截類對象的創建)。但是他們從'object'得到的默認'__eq__'是愚蠢的 - 即使這些類是從相同的源代碼生成的,它們並不相等。這樣對嗎? – wim

+0

對,類對象不是一些singelton類的實例,它們只是'type'元類型的普通實例。調用'type(obj)'不會創建一個新的類型,它只是查找實例'obj'的類型(來自obj .__ class__'),並且返回對該預先存在的對象的引用。 – Blckknght

5

我不知道有關==如何適用於類型的任何文檔,但它絕對符合身份。你可以看到,CPython 2.7 implementation是一個指針比較:

static PyObject* 
type_richcompare(PyObject *v, PyObject *w, int op) 
{ 
    ... 

    /* Compare addresses */ 
    vv = (Py_uintptr_t)v; 
    ww = (Py_uintptr_t)w; 
    switch (op) { 
    ... 
    case Py_EQ: c = vv == ww; break; 

CPython 3.5type沒有實現自己的tp_richcompare,所以它繼承object默認的相等比較,這是一個指針比較:

PyTypeObject PyType_Type = { 
    ... 
    0,           /* tp_richcompare */