2013-07-18 43 views
11

有這樣的代碼:爲什麼不總是根據參數調用__instancecheck__?

class Meta(type): 
    def __instancecheck__(self, instance): 
    print("__instancecheck__") 
    return True 

class A(metaclass=Meta): 
    pass 


a = A() 
isinstance(a, A) # __instancecheck__ not called 
isinstance([], A) # __instancecheck__ called 

爲什麼__instancecheck__被調用[]說法,但不是爲a說法?

+0

這是有關(但不是重複):http://stackoverflow.com/questions/13135712/class-method-instancecheck-does-not-work – dnozay

回答

8

PyObject_IsInstance做了精確匹配的快速測試。

Objects/abstract.c

int 
PyObject_IsInstance(PyObject *inst, PyObject *cls) 
{ 
    static PyObject *name = NULL; 

    /* Quick test for an exact match */ 
    if (Py_TYPE(inst) == (PyTypeObject *)cls) 
     return 1; 
// ... 

不喜歡快速路徑?你可以試試這個(風險自擔):

>>> import __builtin__ 
>>> def isinstance(a, b): 
...  class tmp(type(a)): 
...   pass 
...  return __builtin__.isinstance(tmp(), b) 
... 
>>> __builtin__.isinstance(a, A) 
True 
>>> isinstance(a, A) 
__instancecheck__ 
True 
+1

鑑於此,恕我直言,此代碼有一個錯誤。 – martineau

4

我認爲描述__instancecheck__()的PEP故障。 PEP 3119說:

這裏提出的主要機制是允許超載 內置函數isinstance()和issubclass()。超載 的工作原理如下:調用isinstance(x,C)首先檢查是否存在 C.__instancecheck__,如果存在,則調用C.__instancecheck__(x) 而不是其正常實現。

你可以寫:

class C: 
    def do_stuff(self): 
     print('hello') 

C.do_stuff(C()) 

因此,基於從PEP上面的報價,你應該能夠編寫

class C: 
    @classmethod 
    def __instancecheck__(cls, x): 
     print('hello') 


C.__instancecheck__(C()) 

--output:-- 
hello 

但isinstance()不調用該方法:

class C: 
    @classmethod 
    def __instancecheck__(cls, y): 
     print('hello') 


x = C() 
isinstance(x, C) 

--output:-- 
<nothing> 

然後PEP繼續說:

這些方法旨在叫上一個其元類 是(來源於)ABCMeta ...

好吧,讓我們試試:

import abc 

class MyMeta(abc.ABCMeta): #A metaclass derived from ABCMeta 
    def __instancecheck__(cls, inst): 
     print('hello') 
     return True 

class C(metaclass=MyMeta): #A class whose metaclass is derived from ABCMeta 
    pass 


x = C() 
C.__instancecheck__(x) 

--output:-- 
hello 

但再次isinstance()不會調用該方法:

isinstance(x, C) 

--output:-- 
<nothing> 

結論:PE需要重寫P 3119以及「數據模型」文檔。

相關問題