Subclassing and Inheritance¶
Inheritance¶
In object-oriented programming (OOP), inheritance is a way to reuse code of existing objects, or to establish a subtype from an existing object.
Objects are defined by classes, classes can inherit attributes and behavior from pre-existing classes called base classes or super classes.
The resulting classes are known as derived classes or subclasses.
(http://en.wikipedia.org/wiki/Inheritance_%28object-oriented_programming%29)
Subclassing¶
A subclass “inherits” all the attributes (methods, etc) of the parent class.
You can then change (“override”) some or all of the attributes to change the behavior.
You can also add new attributes to extend the behavior.
The simplest subclass in Python:
class A_subclass(The_superclass):
pass
A_subclass
now has exactly the same behavior as The_superclass
Overriding attributes¶
Overriding is as simple as creating a new attribute with the same name:
class Circle:
color = "red"
...
class NewCircle(Circle):
color = "blue"
>>> nc = NewCircle
>>> print(nc.color)
blue
all the self
instances will have the new attribute.
Overriding methods¶
Same thing, but with methods (remember, a method is an attribute in python)
class Circle:
...
def grow(self, factor=2):
"""grows the circle's diameter by factor"""
self.diameter = self.diameter * factor
...
class NewCircle(Circle):
...
def grow(self, factor=2):
"""grows the area by factor..."""
self.diameter = self.diameter * math.sqrt(2)
all the instances will have the new method
Here’s a program design suggestion:
Whenever you override a method, the interface of the new method should be the same as the old. It should take the same parameters, return the same type, and obey the same preconditions and postconditions.
If you obey this rule, you will find that any function designed to work with an instance of a superclass, like a Deck, will also work with instances of subclasses like a Hand or PokerHand. If you violate this rule, your code will collapse like (sorry) a house of cards.
Overriding __init__¶
__init__
common method to override
You often need to call the super class __init__
as well
class Circle:
color = "red"
def __init__(self, diameter):
self.diameter = diameter
...
class CircleR(Circle):
def __init__(self, radius):
diameter = radius*2
Circle.__init__(self, diameter)
exception to: “don’t change the method signature” rule.
Using the superclasses’ methods¶
You can also call the superclass’ other methods:
class Circle:
...
def get_area(self, diameter):
return math.pi * (diameter/2.0)**2
class CircleR2(Circle):
...
def get_area(self):
return Circle.get_area(self, self.radius*2)
There is nothing special about __init__
except that it gets called
automatically when you instantiate an instance.
When to Subclass¶
“Is a” relationship: Subclass/inheritance
“Has a” relationship: Composition
“Is a” vs “Has a”
You may have a class that needs to accumulate an arbitrary number of objects.
A list can do that – so should you subclass list?
Ask yourself:
– Is your class a list (with some extra functionality)?
or
– Does you class have a list?
You only want to subclass list if your class could be used anywhere a list can be used.
Attribute resolution order¶
When you access an attribute:
an_instance.something
Python looks for it in this order:
- Is it an instance attribute ?
- Is it a class attribute ?
- Is it a superclass attribute ?
- Is it a super-superclass attribute ?
- ...
It can get more complicated...
https://www.python.org/download/releases/2.3/mro/
http://python-history.blogspot.com/2010/06/method-resolution-order.html
What are Python classes, really?¶
Putting aside the OO theory...
Python classes are:
- Namespaces
- One for the class object
- One for each instance
- Attribute resolution order
- Auto tacking-on of
self
when methods are called
That’s about it – really!
Type-Based dispatch¶
You’ll see code that looks like this:
if isinstance(other, A_Class):
Do_something_with_other
else:
Do_something_else
When it’s called for:
isinstance()
issubclass()