In [1]:
from __future__ import print_function

class Animal:
    def __init__(self, name):
        self.name = name
        
    def makeNoise(self):
        print("...")
        
    def saySomething(self):
        print("my name is {0} and I am a {1}".format(self, type(self)))
        self.makeNoise()
        
    def __str__(self):
        return self.name
             
class Dog(Animal):
    def __init__(self, name):
        Animal.__init__(self, name)
        
    def makeNoise(self):
        print("woof!")
        
        
class Cat(Animal):
    def __init__(self, name):
        Animal.__init__(self, name)
                 
    def makeNoise(self):
        print("meow!")

In [2]:
george = Animal('george')
sparky = Dog('sparky')
mitsy = Cat('mitsy')

In [3]:
george.saySomething()


my name is george and I am a <class '__main__.Animal'>
...

In [4]:
sparky.saySomething()


my name is sparky and I am a <class '__main__.Dog'>
woof!

In [5]:
mitsy.saySomething()


my name is mitsy and I am a <class '__main__.Cat'>
meow!

In [6]:
def printAnimal(x):
    if isinstance(x, Animal):
        print("'{0}' is an animal".format(x))
    else:
        print("'{0}' is not an animal".format(x))

In [7]:
printAnimal(george)
printAnimal(sparky)
printAnimal(mitsy)
printAnimal(3)


'george' is an animal
'sparky' is an animal
'mitsy' is an animal
'3' is not an animal