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@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com