snakile
snakile

Reputation: 54571

How do I check (at runtime) if one class is a subclass of another?

Let's say that I have a class Suit and four subclasses of suit: Heart, Spade, Diamond, Club.

class Suit:
   ...
class Heart(Suit):
   ...
class Spade(Suit):
   ...
class Diamond(Suit):
   ...
class Club(Suit):
   ...

I have a method which receives a suit as a parameter, which is a class object, not an instance. More precisely, it may receive only one of the four values: Heart, Spade, Diamond, Club. How can I make an assertion which ensures such a thing? Something like:

def my_method(suit):
   assert(suit subclass of Suit)
   ...

I'm using Python 3.

Upvotes: 275

Views: 178540

Answers (9)

Alexander Lubyagin
Alexander Lubyagin

Reputation: 1494

@snakile, use this code:

#!/usr/bin/python3

class Suit: pass
class Heart(Suit): pass
class Spade(Suit): pass
class Diamond(Suit): pass
class Club(Suit): pass
class No(): pass

suit = Club()
f = issubclass(suit.__class__, Suit)
print(f)

suit = Spade()
f = issubclass(suit.__class__, Suit)
print(f)

suit = No()
f = issubclass(suit.__class__, Suit)
print(f)

Output:

$ /usr/bin/python3 sc.py
True
True
False

Upvotes: 2

YaOzI
YaOzI

Reputation: 17548

According to the Python doc, we can also use class.__mro__ attribute or class.mro() method:

class Suit:
    pass
class Heart(Suit):
    pass
class Spade(Suit):
    pass
class Diamond(Suit):
    pass
class Club(Suit):
    pass

>>> Heart.mro()
[<class '__main__.Heart'>, <class '__main__.Suit'>, <class 'object'>]
>>> Heart.__mro__
(<class '__main__.Heart'>, <class '__main__.Suit'>, <class 'object'>)

Suit in Heart.mro()  # True
object in Heart.__mro__  # True
Spade in Heart.mro()  # False

Upvotes: 7

issubclass minimal runnable example

Here is a more complete example with some assertions:

#!/usr/bin/env python3

class Base:
    pass

class Derived(Base):
    pass

base = Base()
derived = Derived()

# Basic usage.
assert issubclass(Derived, Base)
assert not issubclass(Base, Derived)

# True for same object.
assert issubclass(Base, Base)

# Cannot use object of class.
try:
    issubclass(derived, Base)
except TypeError:
    pass
else:
    assert False

# Do this instead.
assert isinstance(derived, Base)

GitHub upstream.

Tested in Python 3.5.2.

Upvotes: 16

user97370
user97370

Reputation:

You can use issubclass() like this assert issubclass(suit, Suit).

Upvotes: 330

Katriel
Katriel

Reputation: 123782

issubclass(class, classinfo)

Excerpt:

Return true if class is a subclass (direct, indirect or virtual) of classinfo.

Upvotes: 66

Jon Donnelly
Jon Donnelly

Reputation: 11

Using issubclass seemed like a clean way to write loglevels. It kinda feels odd using it... but it seems cleaner than other options.

class Error(object): pass
class Warn(Error): pass
class Info(Warn): pass
class Debug(Info): pass

class Logger():
    LEVEL = Info

    @staticmethod
    def log(text,level):
        if issubclass(Logger.LEVEL,level):
            print(text)
    @staticmethod
    def debug(text):
        Logger.log(text,Debug)   
    @staticmethod
    def info(text):
        Logger.log(text,Info)
    @staticmethod
    def warn(text):
        Logger.log(text,Warn)
    @staticmethod
    def error(text):
        Logger.log(text,Error)

Upvotes: 1

Jameer Mulani
Jameer Mulani

Reputation: 2303

The issubclass(sub, sup) boolean function returns true if the given subclass sub is indeed a subclass of the superclass sup.

Upvotes: 28

XORcist
XORcist

Reputation: 4367

You can use the builtin issubclass. But type checking is usually seen as unneccessary because you can use duck-typing.

Upvotes: 1

David Heffernan
David Heffernan

Reputation: 613592

You can use isinstance if you have an instance, or issubclass if you have a class. Normally thought its a bad idea. Normally in Python you work out if an object is capable of something by attempting to do that thing to it.

Upvotes: 37

Related Questions