260

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.

Boann
  • 48,794
  • 16
  • 117
  • 146
snakile
  • 52,936
  • 62
  • 169
  • 241
  • 2
    @Leopd: Is it really not clear? I have stated exactly what are the possible four values which `my_method` can get as parameters: "it may receive only one of the four values: Heart, Spade, Diamond, Club". Those values are class objects, not class instances. It seems pretty clear to me, though I suppose you're right about the vagueness because the answers do cover both possibilities. You're more than welcome to edit the question if you've got a clearer wordage for it. Thanks for the comment. – snakile Oct 05 '12 at 07:30
  • @snakile yes it is unclear. Due to relying on the correctness of anyone's self-expression is thin ice in this topic. Many newcomers can't get the everything-is-an-object-in-python thing, may express one thing but think another. That's a reality and, purity aside, it's quite rational to expect this behavior from newcomers. Leaving your reputation points the only direct *hint* whether your expression here is correct, or should I say, "in terms of correctness". I understand the wish to take your knowledge into account and it's still irrational not to take into account the ever-renewing newcomers. – n611x007 Aug 28 '14 at 11:22
  • 1
    @snakile that, and the thing that it may be reasonable to use a naming convention that suffixes such parameter names with `_class`, making them like `suit_class`. I [proposed](http://stackoverflow.com/a/25548170/611007) such a naming convention in [a relevant question](http://stackoverflow.com/questions/13765980/what-is-the-naming-convention-for-python-class-references/25548170#25548170). – n611x007 Aug 28 '14 at 12:04
  • Suggest adding to the example code four lines `my_method(Heart)` `my_method(Spade)` ... – Bob Stein Jan 19 '16 at 14:58
  • For cases where the variable being tested is not guaranteed to be a class, you can add a condition on `inspect.isclass` or simply use `isinstance(myvar, type)` in Python 3, as `issubclass` will raise an error if it's passed a non-class. See this [answer](https://stackoverflow.com/a/395782/10682164). I would have commented on the answer below, but it never would have seen the light of day. – totalhack Sep 20 '19 at 17:20
  • The question is inaccurate. It rather asks if an *object* is of a *type* that is a *subclass* of another. This is different from a *type* being *subclass* of another directly. If you have a type, the correct answer doesn't apply. Python naming doesn't help either, using _instance_ and _(sub)class_ for methods with the same signature. I cannot propose editing it because the queue is full. – Eduardo Pignatelli Dec 23 '22 at 13:47

10 Answers10

314

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

Trevor Boyd Smith
  • 18,164
  • 32
  • 127
  • 177
  • You've changed my answer from isinstance to issubclass. You're really passing classes rather than objects around? –  Feb 06 '11 at 12:49
  • 2
    Yes. Each suit is a class, a subclass of Suit. What I want here is four possible values. There are no instances of Suit and there are no instances of Heart, Spade, Club or Diamond. They're singletons. Is that a bad design? – snakile Feb 06 '11 at 13:08
  • 64
    "But why would you want to do such a thing?" -- because you have a container class that you need to ensure is homogeneous, and the only way to do that is to check the type upon insert? – Adam Parkin Jan 12 '12 at 16:39
  • I have a test that ensures my handlers are subclasses of BaseHandler, and that they are not strings. (where they may be lazily imported later) – Rusty Rob May 24 '12 at 04:14
  • 170
    If there's one thing that's a constant on Stack Overflow, it is that any questions with an answer that implies isinstance or issubclass will also be accompanied with lectures about duck typing! – B Robster Feb 12 '13 at 23:21
  • 5
    On the why you would want to do that part. For command line programs I use issubclass against a module's attributes to buildup simple commandline interfaces "my_program.py ", so if I've got my_module.Foo(Command) being collected, you could call `my_program Foo` and it would through introspection call `Foo.Run()` – David May 01 '13 at 17:46
  • 31
    I came across this question trying to figure out how to detect if my numpy dtype is a float or an int for an image processing application. If it's a float, the convention is to normalize between 0.0 and 1.0, if it's int then the convention is 0 to 255. I could go through all sorts of contortions to try and get the image to quack, but it's much more straight forward to just ask "are you a duck" and scale my operations accordingly. – Omegaman Mar 18 '14 at 17:51
  • 6
    A thing to keep in mind: `A class is considered a subclass of itself.` https://docs.python.org/2/library/functions.html#issubclass – frnhr Nov 06 '14 at 22:15
  • 3
    Duck typing doesn't remove use cases for this. Take, for example, Django's signal framework. send_robust returns a tuple of (receiver, response), where response might be the receiver's return value, or it might be an Exception subclass. Using issubclass() to determine which is a perfectly valid use case. – Scott A Mar 04 '15 at 23:47
  • 32
    Subclass testing makes unit testing of many things, particularly Django's models, much easier. "Python is not Java." Why must python programmers have such chips on their shoulders? – Michael Bacon Aug 17 '15 at 18:32
  • 24
    Not upvoting, purely because of the unimaginative and rather arrogant remark at the end. An explanation about why one might not need to do this would be friendlier and more helpful. – Michael Scheper May 09 '16 at 21:08
  • Guess isinstance is enough for most use cases. – Garfield the Dummy Aug 18 '16 at 02:12
  • 1
    `if issubclass(type(e), Exception): logger.exception(...) else: logger.error(...)` – little_birdie Feb 02 '17 at 03:18
  • Can someone explain me "Python is not Java" remark? Can't figure out what does this mean :( – Alex T Jun 29 '17 at 12:10
  • 3
    @AlexT The idea behind python's "duck typing" philosophy is that if an object acts like something else, you should treat it like that and _not_ check if it is the right class before attempting to act upon it. For example, if your function expects a list, but all it does is iterate over the elements in the list, it should just do the iteration without asserting that the variable contains a list. That way someone using your function can pass in a tuple, or an object that acts like a list, and it'll still work instead of breaking unnecessarily. – Izkata Aug 14 '17 at 15:55
  • 2
    @AlexT Java on the other hand is far more strict about this, and you have to make sure the variable is something that supports iteration before attempting to iterate over it. – Izkata Aug 14 '17 at 15:55
  • 2
    Not trying to bash your answer freely, but since it is the accepted one... Your example almost implies one would use `issubclass(instance, Class)` while it really is `issubclass(Class, Superclass)` – Romain Vincent Jul 24 '18 at 15:44
  • 4
    Besides.. I dont find "duck typing" to be more elegant at all. 1 line check to see if it's a duck vs 3 lines of try/catch exception handling. I'll take the 1 line solution.. thanks! – Duane Aug 08 '18 at 03:42
  • Given also the comments, @user97370 didn't deserve so much upvotes, the answer, built collectively, did. – Eduardo Pignatelli Dec 23 '22 at 13:42
60

issubclass(class, classinfo)

Excerpt:

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

Paolo
  • 20,112
  • 21
  • 72
  • 113
Katriel
  • 120,462
  • 19
  • 136
  • 170
33

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.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • What if you find out you can't do that thing with it? Do you catch an exception and try something else? – wrongusername Apr 20 '16 at 20:33
  • 2
    @wrongusername: That is the 'Pythonic' way, yes. I think this custom has merit, so I follow it as long as it keeps my code clear. There's a good discussion about this here: http://stackoverflow.com/questions/7604636/better-to-try-something-and-catch-the-exception-or-test-if-its-possible-first – Michael Scheper May 09 '16 at 21:13
  • 13
    @Michael Scheper: I have to say, if that's the pythonic way, then I really hate the pythonic way. IMO, exceptions should NEVER be used for control flow. If you think an error might occur, protect against it... don't treat it like a GOTO. Interesting link you posted, though – leviathanbadger Apr 07 '17 at 04:51
  • @aboveyou00: Sounds like the kind of cases you're talking about violate 'as long as it keeps my code clear'. I'm not a fan of all Pythonic customs, though, since a lot of people abuse the EAFP principle and end up creating hard-to-find bugs. – Michael Scheper Apr 12 '17 at 19:51
  • This check comes handy when defining contracts. For instance, a constructor that receives an object: we would like to assert that the object received is an instance of a given class, and by doing so we inform the code reader what the constructor expects. – mastropi Apr 29 '20 at 15:56
  • What if I want to print out all subclasses of a superclass? Do I just attempt to print out every class and hope the reader skips over the erroneous lines? Oh wait, but I actually have to print out every object regardless if it's a class or not... What is the point of introspection if we aren't allowed to use it without a lecture on how abnormal it is? – SO_fix_the_vote_sorting_bug Mar 06 '21 at 21:00
26

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

Jameer Mulani
  • 2,253
  • 1
  • 21
  • 15
12

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.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
6

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
YaOzI
  • 16,128
  • 9
  • 76
  • 72
1

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)
1

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

XORcist
  • 4,288
  • 24
  • 32
1

@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
Alexander Lubyagin
  • 1,346
  • 1
  • 16
  • 30
-6
#issubclass(child,parent)

class a:
    pass
class b(a):
    pass
class c(b):
    pass

print(issubclass(c,b))#it returns true
Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
  • 1
    Code-only answers are not appreciated on SO, you should always add some explanatory text to the code. However, this answer is superfluous: it adds no information that hasn't already been mentioned in the previous answers. – PM 2Ring Sep 13 '16 at 13:26