inheritance. inhertance inheritance is used to indicate that one class will get most or all of its...

25
Inheritance

Upload: preston-wilson

Post on 26-Dec-2015

215 views

Category:

Documents


1 download

TRANSCRIPT

Inheritance

Inhertance• Inheritance is used to indicate that one class will

get most or all of its features from a parent class. class Dog(Pet): Make a class Dog that inherits from Pet• When you do this, the language makes any action

that you do on instances of Dog also work as if they were done to an instance of Pet.

• Doing this lets you put common functionality in the Pet class, then specialize that functionality in the Dog class as needed.

class Pet: def __init__(self, name, species): self.name = name self.species = species def getName(self): return self.name def getSpecies(self): return self.species def __str__(self): return “({0} is a {1})" .format(self.name, self.species)

def __init__(self, name, species): (as well as other methods in the Pet class) have this self variable, when you call the method polly = Pet("Polly", "Parrot")you only have to pass in two values.

Why don’t we have to pass in the self parameter? when you call a method of an instance, Python automatically figures out what self should be (from the instance) and

passes it to the function. In the case of __init__, Python first creates self

and then passes it in

• We can also define methods to get the contents of the instance.

• The getName method takes an instance of a Pet as a parameter and looks up the pet’s name.

• Similarly, the getSpecies method takes an instance of a Pet as a parameter and looks up the pet’s species.

• we require the self parameter so that the function knows which instance of Pet to operate on: it needs to be able to find out the content.

def getName(self): return self.namedef getSpecies(self): return self.species

two different ways of calling

• The first way is the standard way of doing it: polly.getName().

• The second, while not conventional, is equivalent: Pet.getName(polly).

• Note how in the second example we had to pass in the instance because we did not call the method via the instance. Python can’t figure out what the instance is if it doesn’t have any information about it.

class Pet: def __init__(self, name, species): self.name = name self.species = species def getName(self): return self.name def getSpecies(self): return self.species def __str__(self): return (“({0} is a {1})" .format(self.name, self.species))

polly = Pet("Polly", "Parrot") polly.getName()Pet.getName(polly)

>>> from pets import Pet>>> polly = Pet("Polly", "Parrot")>>> print (“(Polly is a {0})”.format(polly.getSpecies())) Polly is a Parrot>>> print (“(Polly is a {0})”.format( Pet.getSpecies(polly))) Polly is a Parrot >>> print (“(Polly is a {0})”.format(Pet.getSpecies()))

Traceback (most recent call last): File "", line 1, in TypeError: unbound method getSpecies() must be called with Pet instance as first argument (got nothing instead)

__str__ method

• This __str__ method is a special function that is defined for all.

• You can specify your own version of any built-in method, known as overriding the method.

• By overriding the __str__ method specifically, we can define the behavior when we try to print an instance of the Pet class using the print keyword.

Using Classes

>>> from pets import Pet>>> polly = Pet("Polly", "Parrot") >>> polly.getName() 'Polly‘>>> polly.getSpecies() 'Parrot' >>> print (polly) Polly is a Parrot

Ginger the Cat

>>> from pets import Pet>>> ginger = Pet("Ginger", "Cat") >>> ginger.getName() 'Ginger‘>>> ginger.getSpecies() 'Cat' >>> print (ginger) Ginger is a Cat

Clifford the Dog

>>> from pets import Pet>>> clifford = Pet("Clifford", "Dog")>>> clifford.getName() 'Clifford' >>> clifford.getSpecies() 'Dog‘>>> print (clifford) Clifford is a Dog

Subclasses• Sometimes just defining a single class (like Pet) is

not enough. • For example, some pets are dogs and most dogs

like to chase cats, and maybe we want to keep track of which dogs do or do not like to chase cats.

• Birds are also pets but they generally don’t like to chase cats.

• We can make another class that is a Pet but is also specifically a Dog,

• for example: this gives us the structure from Pet but also any structure we want to specify for Dog.

Dog Class

class Dog(Pet): def __init__(self, name, chases_cats): Pet.__init__(self, name, "Dog") self.chases_cats = chases_cats def chasesCats(self): return self.chases_cats

Define our own initialization function

• We want to specify that all Dogs have species "Dog", and also whether or not the dog likes to chase cats.

• To do this, we need to define our own initialization function (recall that this is known as overriding).

call the parent class initialization function

• We also need to call the parent class initialization function, though, because we still want the name and species fields to be initialized.

• If we did not have Pet.__init__(self, name, "Dog"), then we could still call the methods getName and getSpecies.

• However, because Pet.__init__ was never called, the name and species fields were never created, so calling getName or getSpecies would throw an error.

We can define a similar subclass for cats: Cat Class

class Cat(Pet): def __init__(self, name, hates_dogs): Pet.__init__(self, name, "Cat") self.hates_dogs = hates_dogs def hatesDogs(self): return self.hates_dogs

Let’s examine the difference between Dog and Pet

>>> from pets import Pet, Dog >>> mister_pet = Pet("Mister", "Dog")>>> mister_dog = Dog("Mister", True)

isinstance()

• isinstance() is a special function that is used to see if an instance is an instance of a certain type of class.

• Here we can see that mister_pet is an instance of Pet, but not Dog, while mister_dog is an instance of both Pet and Dog:

>>> isinstance(mister_pet, Pet) True>>> isinstance(mister_pet, Dog) False>>> isinstance(mister_dog, Pet) True>>> isinstance(mister_dog, Dog) True

• Because mister_pet is a Pet, but not a Dog, we can’t call chasesCats on it because the Pet class has no chasesCats method.

• We can, however, call chasesCats on mister_dog, because it is defined for the Dog class.

• Conversely, we can call the getName method on both mister_pet and mister_dog because they are both instances of Pet, even though getName is not explicitly defined in the Dog class.

>>> mister_pet.chasesCats() Traceback (most recent call last): File "", line 1, in

AttributeError: 'Pet' object has no attribute 'chasesCats'

>>> mister_dog.chasesCats() True >>> mister_pet.getName() 'Mister‘>>> mister_dog.getName() 'Mister'

Cats and DogsNow let’s create some cats and dogs.

>>> from pets import Cat, Dog >>> fido = Dog("Fido", True)>>> rover = Dog("Rover", False) >>> mittens = Cat("Mittens", True)>>> fluffy = Cat("Fluffy", False)>>> print (fido) Fido is a Dog>>> print (rover) Rover is a Dog >>> print (mittens) Mittens is a Cat >>> print (fluffy) Fluffy is a Cat

>>> print (“({0} chases cats: {1})".format(fido.getName(),fido.chasesCats())) Fido chases cats: True>>> print (“({0} chases cats: {1})".format(rover.getName(),rover.chasesCats())) Rover chases cats: False >>> print (“({0} hates dogs : {1})".format(mittens.getName(), mittens.hateDogs())) Mittens hates dogs: True>>> print (“({0} hates dogs : {1})".format(fluffy.getName(), fluffy.hatesDogs())) Fluffy hates dogs: False

http://www.jesshamrick.com/2011/05/18/an-introduction-to-classes-and-inheritance-in-python/