Reputation: 16199
According to Learn Python The Hard Way ex44 and the explantion of using super()
with __init__
:
class Child(object):
def __init__(self, stuff):
self.stuff = stuff
super(Child, self).__init__()
This is pretty much the same as the
Child.altered
example above, except I'm setting some variables in the__init__
before having theParent
initialize with itsParent.__init__.
So instantiating Child
causes also an instantiation of Parent
. But what/where is this instantiation? Given:
c = Child()
where/what is the Parent
object?
Upvotes: 1
Views: 96
Reputation: 78700
super(Child, self)
gives you the object which self
is pointing to as an instance of the parent class of Child
(which is Parent
).
In the __init__
method of Child
you first do some stuff (self.stuff = stuff
) and then call the __init__
method of Parent
on your Child
object which self
is pointing to!
You are not instantiating a Parent
object explicitly, but because of inheritance every Child
is a Parent
.
@timgeb a practical usage example, or justification for using super() in this way, would be helpful.
Sure, let's look at a simple example. Let's say you are building an application for a postal service. The service delivers several kinds of items such as packages, letters or postcards. Each of these items share some properties. To keep it simple, let's say they share the name of the receiver (in a real world application, you would probably need more properties such as the full address of the receiver).
>>> class MailItem(object):
... def __init__(self, receiver_name):
... self.receiver_name = receiver_name
...
>>> m = MailItem('Pyderman')
>>> m.receiver_name
'Pyderman'
This seems to work fine. However, our MailItem
is far too unspecific. What if the item is a package? Then we would certainly care about its weight. On the other hand, if the item is a postcard, the weight would be irrelevant. Let's create a child class for the packages called Package
which inherits from MailItem
. Every Package
object is-a MailItem
, but it will store extra information about its weight.
>>> class Package(MailItem):
... def __init__(self, receiver_name, weight):
... # treat the package as a MailItem and call the MailItem initializier
... super(Package, self).__init__(receiver_name)
... # store extra information about the weight in some arbitrary unit
... self.weight = weight
When we instantiate a Package
, the first thing we do is to call the initializer of MailItem
, because every Package
is also a MailItem
. This will not create another MailItem
object, but call the __init__
method of MailItem
on our new Package
object. In this example, we could have achieved the same thing by copying the line self.receiver_name = receiver_name
from the initializer of MailItem
into the initializer of Package
instead of using super
, but that would be duplicate code and go against the Dont-Repeat-Yourself principle.
Let's instantiate a Package
to see the code at work.
>>> p = Package('Pyderman', 200)
>>> p.receiver_name
'Pyderman'
>>> p.weight
200
As you can see, the object p
does have a receiver_name
, because the initializer of Package
calls the MailItem
initializer via
super(Package, self).__init__(receiver_name)
.
At the risk of repeating myself, to make one thing crystal clear:
We are only creating one Package
object with p = Package('Pyderman', 200)
, not an additional MailItem
object. Every Package
object is-a MailItem
, and Python will tell you so:
>>> isinstance(p, MailItem)
True
Of course, every Package
is also a Package
.
>>> isinstance(p, Package)
True
However, not every MailItem
is-a Package
:
>>> m = MailItem('Pyderman')
>>> isinstance(m, Package)
False
Think about it this way: every crocodile is a reptile, but not every reptile is a crocodile.
Upvotes: 3
Reputation: 155036
Not instantiation, initialization - carefully read the passage you quoted and you'll see it only mentions the latter. Initialization (sometimes historically also referred to as construction) is the process of building up an empty instance into a usable object of the given type.
Parent.__init__
results in a usable Parent
object; Child.__init__
builds upon that to create a usable Child
object. Thus, every Child
object is by extension also a valid Parent
object.
Upvotes: 2