[Python-Dev] Semantic of isinstance

Maric Michaud maric at aristote.info
Tue Jun 27 09:29:12 CEST 2006


Le mardi 27 juin 2006 05:38, Phillip J. Eby a écrit :
> At 05:16 PM 6/26/2006 -0700, Martin Maly wrote:
> > >>> class D(object):
> >
> >...     def getclass(self):
> >...         print "D.getclass"
> >...         return C
> >...     __class__ = property(getclass)
> >...
> >
> > >>> isinstance(D(), D)
> >
> >True
> >
> > >>> isinstance(D(), C)
> >
> >D.getclass
> >True
> >
> >isinstance in this case returns True to both C and D test. I would expect
> >
> >to see the __class__ property being called in both cases and get:
> > >>> isinstance(D(), D)
> >
> >D.getclass
> >False
> >
> >but that's not the case for some reason.
>
> That's because isinstance checks type(D()) and finds it equal to D -- this
> shortcuts the process.
>
> >  It seems that the __class__ is only accessed in some cases, but not
> > always, leading to what I think is a semantic inconsistency.
>
> It's not inconsistent - isinstance() checks __class__ in *addition* to
> type() in order to allow proxying tricks like lying about your
> __class__.  It therefore returns true if either your real type *or* your
> __class__ matches, and as you can see, the real type is checked first.
>
> >class E(object):
> >     def getbases(self):
> >         print "E.getbases"
> >         return ()
> >     __bases__ = property(getbases)
> >
> >class C(object):
> >     def getbases(self):
> >         print "C.getbases"
> >         return (E,)                     # C() claims: "E is my base
> > class" __bases__ = property(getbases)
> >
> >class D(object):
> >     def getclass(self):
> >         print "D.getclass"
> >         return C()                      # D() claims: "C() is my
> > __class__" __class__ = property(getclass)
> >
> >
> >class F(object): pass
> >
> >
> >print "Test 1"
> >print isinstance(D(), E())              # testing against E() instance
> >print "Test 2"
> >print isinstance(D(), E)                # testing against E class
> >
> >The output here is:
> >
> >Test 1
> >E.getbases
> >D.getclass
> >C.getbases
> >False
> >
> >Test 2
> >D.getclass
> >False
> >
> >In the 2nd test, D.getclass is called to get the __class__ of D(), which
> >returns C() instance. At this point I would expect that C.getbases gets
> >called as __bases__ are retrieved, which would return tuple consisting of
> >E and ultimately produce True result.
>
> As it happens, this is due to the fact that E is a type, while E() is
> not.  There's an optimization in the isinstance() machinery that simply
> checks to see if D().__class__ is a subtype of E.  That's where your
> experiment fails.
>
> I'm not sure whether this behavior should be considered correct or not.
>
> _______________________________________________
> Python-Dev mailing list
> Python-Dev at python.org
> http://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe:
> http://mail.python.org/mailman/options/python-dev/maric%40aristote.info

Doesn't seems to be just related to isinstance implementation, furthermore, it 
is very surprising that old-style and new style classes behave exactly the 
opposite way.

In [2]: class a(object) :
   ...:     __class__ = 0
   ...:
   ...:

In [3]: a.__class__
Out[3]: <type 'type'>

In [4]: a().__class__
Out[4]: 0

In [7]: class a :
   ...:     __class__ = 0
   ...:
   ...:

In [8]: a.__class__
Out[8]: 0

In [9]: a().__class__
Out[9]: <class __main__.a at 0xa78cb4ac>

-- 
_____________

Maric Michaud
_____________

Aristote - www.aristote.info
3 place des tapis
69004 Lyon
Tel: +33 426 880 097


More information about the Python-Dev mailing list