2013-07-18 12 views
11

Jest to kod:Dlaczego funkcja __instancheckheck__ nie zawsze jest wywoływana w zależności od argumentu?

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 

Dlaczego __instancecheck__ nazywa dla [] argumentu, ale nie dla a argumentu?

+0

jest to związane z (ale nie duplikatem): http://stackoverflow.com/questions/13135712/class-method-instancecheck-does-notwork-work – dnozay

Odpowiedz

8

PyObject_IsInstance wykonuje szybki test dla dokładnego dopasowania.

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; 
// ... 

nie lubią szybką ścieżkę? można spróbować (na własne ryzyko):

>>> 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

Biorąc pod uwagę, że IMHO ten kod ma błąd. – martineau

4

myślę, że PEP opisując __instancecheck__() jest uszkodzony. PEP 3119 mówi:

Podstawowy mechanizm zaproponowany tutaj jest umożliwienie przeciążania wbudowane funkcje isinstance() i issubclass(). Przeciążanie działa w następujący sposób: Wywołanie isinstance (x, C) najpierw sprawdza, czy istnieje C.__instancecheck__, a jeśli tak, wywołuje C.__instancecheck__(x) zamiast jego normalnej implementacji.

Można napisać:

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

C.do_stuff(C()) 

Więc na podstawie cytatu powyżej z PEP, powinieneś być w stanie napisać

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


C.__instancecheck__(C()) 

--output:-- 
hello 

Ale isinstance() nie wywołać tej metody:

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


x = C() 
isinstance(x, C) 

--output:-- 
<nothing> 

Następnie PEP mówi:

Metody te są przeznaczone do być nazywane na zajęciach, których metaklasa jest (pochodzący z) ABCMeta ...

Dobra, spróbujmy, że:

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 

ale po raz kolejny isinstance() nie nazywa tej metody:

isinstance(x, C) 

--output:-- 
<nothing> 

Wniosek: PE P 3119 musi zostać przepisany - wraz z dokumentami "Model danych".

Powiązane problemy