Test an object is a subclass of the type of another instance

A-P picture A-P · Dec 14, 2014 · Viewed 15.6k times · Source

I have this code:

class Item:
    def __init__(self,a):
        self.a=a

class Sub(Item):
    def __init__(self,a,b):
        self.b=b
        Item.__init__(self,a)

class SubSub(Sub):
    def __init__(self,a,b,c):
       self.c=c
       Sub.__init__(self,a,b)

obj1=Item(1)
obj2=Sub(1,2)
obj3=SubSub(1,2,3)

Now I want to check if obj2 and obj3 are instances of classes that are subclasses of obj1 as well as simply subclasses of of Item.

Here is what I understand, I know that I can use the isinstance() to find if obj2 is Sub. and I know that I can use issubclass(Sub, Item). But let's say I didn't know what class obj2 was.

I tried using issubclass(type(obj2),Item) but that doesn't work, because type() returns a separate object that I don't really understand the workings of. And this is just one problem, although I figure that the answer to this question will help me solve some of the other problems that I am having.

Also I have tried using some of the special attributes to do this such as __class__ but I can't figure out how to do that either.

Answer

Martijn Pieters picture Martijn Pieters · Dec 14, 2014

You'd need to extract the type of obj with the type() function:

isinstance(obj2, type(obj1))

Note that the second argument is the class, the first is the instance to test. type() is returning the actual class object here, not any separate object.

issubclass() works just fine for your usecase:

issubclass(type(obj2), Item)

Demo:

>>> class Item:
...     def __init__(self,a):
...         self.a=a
... 
>>> class Sub(Item):
...     def __init__(self,a,b):
...         self.b=b
...         Item.__init__(self,a)
... 
>>> class SubSub(Sub):
...     def __init__(self,a,b,c):
...        self.c=c
...        Sub.__init__(self,a,b)
... 
>>> obj1=Item(1)
>>> obj2=Sub(1,2)
>>> obj3=SubSub(1,2,3)
>>> isinstance(obj2, type(obj1))
True
>>> issubclass(type(obj2), Item)
True

Note that if you re-defined the classes here, existing instances will not be updated to point to the new class objects. If type(obj2) doesn't work for you, then that means that the class used to produce it is not the same you are testing with now.

You can test if this the case by testing your assumptions; validate that the classes and instances are still in sync, for example:

>>> type(obj1) is Item
True
>>> type(obj2) is Sub
True
>>> type(obj3) is SubSub
True