Week 10-11 - State University of Zanzibar

Download Report

Transcript Week 10-11 - State University of Zanzibar

Week 10-11
Inheritance and Polymorphism
Introduction
• Classes allow you to modify a program
without really making changes to it.
• To elaborate, by subclassing a class, you can
change the behavior of the program by simply
adding new components to it rather than
rewriting the existing components.
Introduction
• As we’ve seen, an instance of a class inherits the
attributes of that class.
• However, classes can also inherit attributes from
other classes.
• Hence, a subclass inherits from a superclass
allowing you to make a generic superclass that is
specialized via subclasses.
• The subclasses can override the logic in a
superclass, allowing you to change the behavior
of your classes without changing the superclass
at all.
Inheritance
• In object-oriented programming (OOP),
inheritance is when an object or class is based
on another object or class, using the same
implementation, it is a mechanism for code
reuse.
• The relationships of objects or classes through
inheritance give rise to a hierarchy.
• Inheritance was invented in 1967 for Simula.
Inheritance
• In some languages, inheritance implements ISA Relationship.
• There are various types of inheritance,
depending on paradigm and specific language.
Types of Inheritance
• Single Inheritance can inherit from only a
single other object or class.
• Multiple Inheritance can inherit from multiple
other objects or classes.
• The hierarchy in single inheritance is a tree,
while in multiple inheritance it is a lattice.
Tree
Lattice
Types of Inheritance
• Classical inheritance is used in class-based
programming, where objects are defined by
classes, and classes can inherit attributes and
implementation (i.e., previously coded algorithms
associated with a class) from pre-existing classes
called base classes, superclasses, or parent
classes.
• The resulting classes are known as derived
classes, subclasses, or child classes, and the
resulting hierarchy is known as a class hierarchy.
Types of Inheritance
• Differential inheritance is used in prototypebased programming, where objects inherit
directly from other objects.
Subclasses and superclasses
• A Subclass, "derived class", heir class, or child
class is a modular, derivative class that inherits
one or more language entities from one or
more other classes (called superclasses, base
classes, or parent classes).
cont
• The semantics of class inheritance vary from
language to language, but commonly the
subclass automatically inherits the instance
variables and member functions of its
superclasses.
• Some languages support the inheritance of
other construct as well. For example, in Eiffel,
contracts which define the specification of a
class are also inherited by heirs.
cont
• The superclass establishes a common
interface and foundational functionality,
which specialized subclasses can inherit,
modify, and supplement.
• The software inherited by a subclass is
considered reused in the subclass.
• A reference to an instance of a class may
actually be referring one of its subclasses.
cont
• The actual class of the object being referenced
is impossible to predict at compile-time.
• A uniform interface is used to invoke the
member functions of objects of a number of
different classes.
• Subclass may replace superclass functions
with entirely new functions that must share
the same method signature.
Uninheritable Class
• In some languages a class may be declared as
uninheritable by adding certain class modifiers to
the class declaration.
• Examples include the "final" keyword in Java or
the "sealed" keyword in C#. Such modifiers are
added to the class declaration before the "class"
keyword and the class identifier declaration.
• Such sealed classes restrict reusability,
particularly when developers only have access to
precompiled binaries and not source code.
Using Inheritance
• Implementation inheritance is the mechanism
whereby a subclass re-uses code in a base
class.
• By default the subclass retains all of the
operations of the base class, but the subclass
may override some or all operations, replacing
the base-class implementation with its own.
Superclass
• Defining a superclass:
• class FirstClass : #define the superclass
• def setdata( self , value) : #define methods
self . data = value #’ self ’ refers to an instance
def display( self ) :
print(self . data)
Subclass
• Defining a subclass:
• class SecondClass(FirstClass ) : #inherits from
#FirstClass
def display( self ) : #redefines ’display ’
print("Current value = ’%s ’" % self .
data)
cont
• As you can see, SecondClass “overwrites” the
display method.
• When a FirstClass instance is created, all of its
actions will be taken from the methods
defined in FirstClass.
• When a SecondClass instance is created, it will
use the inherited setdata() method from
FirstClass but the display method will be the
one from SecondClass.
Example Continue
• To make this easier to understand, here are some
examples in practice.
• >>>x=FirstClass () #instance of FirstClass
>>>y=SecondClass() #instance of SecondClass
>>>x. setdata("The boy called Brian .")
• >>>y. setdata (42)
• >>>x. display ()
• The boy called Brian .
• >>>y. display ()
• Current value = ’42 ’
Explainantion
• Both instances (x and y) use the same
setdata() method from FirstClass; x uses it
because it’s an instance of FirstClass while y
uses it because SecondClass inherits setdata()
from FirstClass.
• However, when the display method is called, x
uses the definition from First- Class but y uses
the definition from SecondClass, where
display is overridden.
cont
• Because changes to program logic can be
made via subclasses, the use of classes
generally supports code reuse and extension
better than traditional functions do.
• Functions have to be rewritten to change how
they work whereas classes can just be
subclassed to redefine methods.
Redefining Methods
• Very similar to over-riding methods in Java
• To redefine a method of the parent class,
include a new definition using the same name
in the subclass.
• The old code won’t get executed.
• To execute the method in the parent class in
addition to new code for some method,
explicitly call the parent’s version of the
method.
cont
• parentClass.methodName(self, a, b, c)
• The only time you ever explicitly pass ‘self’ as
an argument is when calling a method of an
ancestor.
Extending __init__
• Very similar to Java
• Commonly, the ancestor’s __init__ method is
executed in addition to new commands.
• Must be done explicitly
• You’ll often see something like this in the __init__
method of subclasses:
• parentClass.__init__(self, x, y)
• where parentClass is the name of the parent’s
class.
Example
• class Person:
def speak(self):
print(“I can speak”)
class Man(Person):
def wear(self):
print(“I wear shirt”)
class Woman(Person):
def wear(self):
print(“I wear skirt”)
man = Man()
man.wear()
man.speak()
>>> I wear shirt
I can speak
Multiple Inheritance
• Python supports a limited form of multiple
inheritance.
• A class definition with multiple base classes
looks as follows:
• class DerivedClass(Base1, Base2, Base3 …)
<statement-1>
<statement-2>
…
cont
• The only rule necessary to explain the
semantics is the resolution rule used for class
attribute references.
• This is depth-first, left-to-right.
• Thus, if an attribute is not found in
DerivedClass, it is searched in Base1, then
recursively in the classes of Base1, and only if
it is not found there, it is searched in Base2,
and so on.
Example of Multiple Inheritance
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
class A:
def A(self):
print(“I am A”)
class B:
def A(self):
print(“I am a”)
def B(self):
print(“I am B”)
class C(A, B):
def C(self):
print(“I am C”)
C = C()
C.A()
C.B()
C.C()
Explanation
• C multiple-inherit A and B, but since A is in the
left of B, so C inherit A and invoke A.A()
according to the left-to-right sequence.
• To implement C.B(), class A does not have B()
method, so C inherit B for the second priority.
So C.B() actually invokes B() in class B.
Method Overriding
• Method overriding means having a different
implementation of the same method in the
inherited class.
• These two methods would have the same
signature, but different implementation.
• One of these would exist in the base class and
another in the derived class. These cannot
exist in the same class.
Overriding Method Definitions
• In a derived class, if you include a method
definition that has the same name and exactly
the same number and types of parameters as
a method already defined in the base class,
this new definition replaces the old definition
of the method.
Explanation
• A subclass inherits methods from a superclass.
Sometimes, it is necessary for the subclass to
modify the methods defined in the superclass.
This is referred to as method overriding.
• The following example demonstrates method
overriding.
Example
• import math
• class Circle:
•
# declaring the instance variable
•
radius = 0.0
•
def Circle(self, radius):
•
self.radius = radius
•
# other method definitions here
•
def getArea(self):
•
#this method returns the area of the circle
return math.pi*pow(self.radius,2)
cont
• When the getArea method is invoked from an
instance of the Circle class, the method returns
the area of the circle.
• The next step is to define a subclass to override
the getArea() method in the Circle class.
• The derived class will be the Cylinder class.
• The getArea() method in the Circle class
computes the area of a circle, while the getArea
method in the Cylinder class computes the
surface area of a cylinder.
Derived Class
• class Cylinder(Circle):
•
# declaring the instance variable
•
length = 0.0
•
def Cylinder(self, radius, length):
•
self.radius = radius
•
self.length = length
•
Circle(self.radius)
•
# other method definitions here
•
def getArea(self):
•
#this method returns the cylinder surface area
•
return 2*Circle.getArea(self) + 2*math.pi*self.radius*self.length
Test Code
• When the overriden method (getArea) is
invoked for an object of the Cylinder class, the
new definition of the method is called and not
the old definition from the superclass(Circle).
Test Code
•
•
•
•
•
•
MyCircle = Circle(1.2)
MyCylinder = Cylinder(1.2, 2.5)
A = MyCircle.getArea()
B = MyCylinder.getArea()
print(“Area of the circle is: “, A)
print(“Area of the cylinder is: “, B)
Association
• In object-oriented programming, association
defines a relationship between classes of
objects that allows one object instance to
cause another to perform an action on its
behalf. This relationship is structural, because
it specifies that objects of one kind are
connected to objects of another and does not
represent behaviour.
Association
• In generic terms, the causation is usually
called "sending a message", "invoking a
method" or "calling a member function" to
the controlled object.
• Concrete implementation usually requires the
requesting object to invoke a method or
member function using a reference or pointer
to the memory location of the controlled
object.
Association
• The objects that are related via the association
are considered to act in a role with respect to the
association, if object's current state in the active
situation allows the other associated objects to
use the object in the manner specified by the
role. A role can be used to distinguish two objects
of the same class when describing its use in the
context of the association. A role describes the
public aspects of an object with respect to an
association.
Association
• Association implements USES-A Relationship
Protected Access Levels
• Generations of Pythonistas have mangled
their variables with a double underscore "__"
to enable data hiding as in C++ or Java. But
this was always only an adaequate solution for
preventing name clashes between a class and
its superclass. The term "privacy" had a very
different meaning.
Protected Access Levels
• Opposite to the standard semantics where
each Python variable is essentially public,
applying the above recipe it becomes basically
"protected" i.e. visible only to the class where
it is defined and to subclasses. In order to
make an attribute public it has to be made
public explicitely using either the public()
decorator ( for methods only ) or the class
attribute __public__.
Tip
• Remember Private, Public, Data Hiding?
Polymorphism
• Polymorphism exists when you define a number
of subclasses which have commonly named
methods.
• In some languages, it is essential that the
polymorphic classes have the same interface (or
be subinterfaces of a common parent interface),
or be subclasses of a common superclass.
• This is sometimes called "strong, hierarchical
typing", since the type rules are very rigid and
follow the subclass/subinterface hierarchy.
Polymorphism
• Let’s look at the examples for Card, FaceCard, and
Ace, we see that all three classes have the same
method names, but have different
implementations for some of these methods.
• These three classes are polymorphic.
• A client class like Hand can contain individual
objects of any of the subclasses of Card.
• A function can evaluate these polymorphic
methods without knowing which specific subclass
is being invoked.
Class Card
• class Card( object ):
• """A standard playing card for Blackjack.""" def
__init__( self, r, s ):
self.rank, self.suit = r, s
self.pval= r
def __str__( self ):
return "%2d%s" % ( self.rank, self.suit )
def getHardValue( self ):
return self.pval
def getSoftValue( self ):
return self.pval
Class FaceCard
• class FaceCard( Card ):
• """A 10-point face card: J, Q, K."""
• def __init__( self, r, s ):
super(FaceCard,self).__init__( r, s )
•
self.pval= 10
• def __str__( self ):
•
label= ("J","Q","K")[self.rank-11]
•
return "%2s%s" % ( label, self.suit )
Class Ace
•
•
•
•
•
•
•
•
class Ace( Card ):
"""An Ace: either 1 or 11 points."""
def __str__( self ):
return "%2s%s" % ( "A", self.suit )
def getHardValue( self ):
return 1
def getSoftValue( self ):
return 11
Class Hand
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
class Hand( object ):
"""Model a player's hand."""
def __init__( self ):
self.cards = [ ]
self.softDiff= 0
def addCard( self, aCard ):
self.cards.append( aCard )
if aCard.getHardValue() != aCard.getSoftValue():
if self.softDiff == 0:
self.softDiff= aCard.getSoftValue()-aCard.getHardValue() def points( self ):
"""Compute the total points of cards held."""
p= 0
for c in self.cards:
p += c.getHardValue()
if p + self.softDiff <= 21:
return p + self.softDiff
else:
return p
Polymorphism
• Polymorphism is the ability to use the same
syntax for objects of different types. (Strictly
speaking, this is ad-hoc polymorphism.)
• For example, in Python, the square bracket
operator is used to perform indexing of various
sequence types (list[3], dict["foo"]).
• Polymorphism allows us to define our own types,
as classes, that emulate builtin Python types like
sequences and which therefore can use e.g.
square brackets for indexing.
Polymorphism
• The polymorphism is the process of using an
operator or function in different ways for
different data input. In practical terms,
polymorphism means that if class B inherits
from class A, it doesn’t have to inherit
everything about class A; it can do some of
the things that class A does differently.
Example
•
•
•
•
•
•
•
•
#!/usr/bin/python
# basic.py
a = "alfa"
b = (1, 2, 3, 4)
c = ['o', 'm', 'e', 'g', 'a']
print a[2]
print b[1]
print c[3]
explained
• Python programming language uses
polymorphism extensively in built-in types.
Here we use the same indexing operator for
three different data types.
• $ ./basic.py
• f
• 2
• g
Polymorphism
• Polymorphism is most commonly used when
dealing with inheritance.
Example
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
#!/usr/bin/python
# polymorphism.py
class Animal:
def __init__(self, name=''):
self.name = name
def talk(self):
pass
class Cat(Animal):
def talk(self):
print "Meow!"
class Dog(Animal):
def talk(self):
print "Woof!"
a = Animal()
a.talk()
c = Cat("Missy")
c.talk()
d = Dog("Rocky")
d.talk()
Explained
• Here we have two species. A dog and a cat.
Both are animals. The Dog class and the Cat
class inherit the Animal class. They have a
talk() method, which gives different output for
them.
• $ ./polymorphism.py
• Meow!
• Woof!