63

I'm new to Python... and coming from a mostly Java background, if that accounts for anything.

I'm trying to understand polymorphism in Python. Maybe the problem is that I'm expecting the concepts I already know to project into Python. But I put together the following test code:

class animal(object):
    "empty animal class"

class dog(animal):
    "empty dog class"

myDog = dog()
print myDog.__class__ is animal
print myDog.__class__ is dog

From the polymorphism I'm used to (e.g. java's instanceof), I would expect both of these statements to print true, as an instance of dog is an animal and also is a dog. But my output is:

False
True

What am I missing?

froadie
  • 79,995
  • 75
  • 166
  • 235
  • 17
    Note that checking an object's type is the opposite of polymorphism. Polymorphism is operating on an object regardless of its type. – dash-tom-bang May 14 '10 at 18:28
  • This question is premised on a misunderstanding: `isinstance(myDog, animal)` does what you're looking for, `myDog.__class__ is animal` is wrong. Also in Python we use MixedCase for class names but lower_case_with_underscores for object names. So your classes should be called `Animal, Dog` and your object `my_dog, dog1` etc. – smci Dec 31 '19 at 17:24
  • 2
    Really your question title should be *"How to test if an object is an instance of specified class or its subclasses?"* But inspecting an object's class is the opposite of polymorphism, which counts on methods to exist, be implemented, and do the appropriate thing (or raise appropriate exception), as @dash-tom-bang says. – smci Jan 01 '20 at 10:17
  • @anjaneyulubatta505 the link is not working. – Idonknow Apr 19 '20 at 14:33
  • @Idonknow Try reading https://learnbatta.com/blog/python-polymorphism-62/ – anjaneyulubatta505 Apr 19 '20 at 15:45

4 Answers4

78

The is operator in Python checks that the two arguments refer to the same object in memory; it is not like the is operator in C#.

From the docs:

The operators is and is not test for object identity: x is y is true if and only if x and y are the same object. x is not y yields the inverse truth value.

What you're looking for in this case is isinstance.

Return true if the object argument is an instance of the classinfo argument, or of a (direct or indirect) subclass thereof.

>>> class animal(object): pass

>>> class dog(animal): pass

>>> myDog = dog()
>>> isinstance(myDog, dog)
True
>>> isinstance(myDog, animal)
True

However, idiomatic Python dictates that you (almost) never do type-checking, but instead rely on duck-typing for polymorphic behavior. There's nothing wrong with using isinstance to understand inheritance, but it should generally be avoided in "production" code.

Mark Rushakoff
  • 249,864
  • 45
  • 407
  • 398
  • 2
    For classes which inherit from `object` you can also look at the `classname.__mro__` tuple, but really, that's useful more for educational purposes. – detly May 14 '10 at 16:34
43

phimuemue and Mark have answered your question. But this is ALSO an example of polymorphism in Python, but it's not as explicit as your inheritance based example.

class wolf(object): 
    def bark(self):
        print "hooooowll"

class dog(object): 
    def bark(self):
        print "woof"


def barkforme(dogtype):
    dogtype.bark()


my_dog = dog()
my_wolf = wolf()
barkforme(my_dog)
barkforme(my_wolf)
Pod
  • 3,938
  • 2
  • 37
  • 45
11

Try isinstance(myDog, dog) resp. isinstance(myDog, animal).

phimuemue
  • 34,669
  • 9
  • 84
  • 115
0

just nice example how it is possible to use same field of 2 totally different classes. It is more close to template.

class A:
    def __init__(self, arg = "3"):
        self.f = arg
a = A()
a.f # prints 3
class B:
    def __init__(self, arg = "5"):
        self.f = arg
b = B()
b.f # prints 5


def modify_if_different(s,t, field):
    if s.__dict__[field] != t.__dict__[field]:
        t.__dict__[field]  = s.__dict__[field]
    else:
        s.__dict__[field]  = None

modify_if_different(a,b,"f")
b.f # prints 3
a.f # prints 3