[Python-Dev] Semantic of isinstance

Martin Maly Martin.Maly at microsoft.com
Tue Jun 27 02:16:45 CEST 2006


Hello Python Dev,

I am trying to understand the correct semantic of the isinstance built-in function and while doing so, I came across few cases which raise some questions.

1) First example - a class instance pretends to have different class via __class__.

>>> 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. It seems that the __class__ is only accessed in some cases, but not always, leading to what I think is a semantic inconsistency.

2) Second, slightly more complicated example, uses an instance with __bases__ on it as the 2nd parameter to isinstance:

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. However, in this case the __bases__ are never accessed on C() (the class of D()). The test_isinstance.py actually tests for similar case.

My question is based on what assumptions does the standard Python implementation bypass the access to __bases__, __class__ etc. when evaluating isinstance? Did I happen to come across a bug or an inconsistency in Python implementation, or am I hitting an intentional behavior?

Thanks very much for reading and some insights!
Martin


More information about the Python-Dev mailing list