[Tutor] Re: Inheritance
Gonçalo Rodrigues
op73418 at mail.telepac.pt
Thu Dec 18 11:43:39 EST 2003
On Wed, 17 Dec 2003 13:50:27 -0700, you wrote:
I'm forwarding this back to the list. Always reply (also) to the list,
since other people may learn and possibly even correct me!
>
>Thanks a lot that was really helpful. Couple questions though.
>In this part why is C called before B??
>
This is just a concequence of the linearization algorithm. There is a
paper on the web by Michele Simionato explaining the one that made it
in 2.3. It's called C3 and was borrowed from Dylan.
http://www.python.org/2.3/mro.html
This is heavy stuff (at least it is for me) - you've been warned.
>>>> class D(B,C):
>... def __init__(self):
>... super(D, self).__init__()
>... print "D"
>...
>>>> d = D()
>A
>C
>B
>D
>>>>
>
>Also(I hope I dont regret asking)
>
>How does Super make sure that only 1 instance of A is called
Why don't we explore it together? To give a convenient, accurate and
100% correct picture we would have to go down to the bowels of the C
implementation, and this is a Python Tutor list not a C Tutor list.
Besides, I haven't touched C in more than 10 years so it's like Huh,
isn't C the third letter in the alphabet? So i'll just try to give a
mental picture of how things work - as I understand them, if anyone is
reading, feel free to correct me!:
First, super returns an *object* as you can see from the online help:
Help on class super in module __builtin__:
class super(object)
| super(type) -> unbound super object
| super(type, obj) -> bound super object; requires isinstance(obj,
type)
| super(type, type2) -> bound super object; requires
issubclass(type2, type)
...
As such we can ask what are its attributes:
>>> for elem in dir(super):
... print elem
...
__class__
__delattr__
__doc__
__get__
__getattribute__
__hash__
__init__
__new__
__reduce__
__reduce_ex__
__repr__
__self__
__self_class__
__setattr__
__str__
__thisclass__
Everything is standard here except those misteryous __thisclass__ and
__self_class__ attributes. Let us try to see what they give in a
concrete case. Let us go back to our diamond inheritance graph and
write the __init__ methods as
>>> class A(object):
... def __init__(self):
... print "A"
...
>>> class B(A):
... def __init__(self):
... obj = super(B, self)
... print obj.__thisclass__
... print obj.__self_class__
... obj.__init__()
...
>>> class C(A):
... def __init__(self):
... obj = super(C, self)
... print obj.__thisclass__
... print obj.__self_class__
... obj.__init__()
...
>>> class D(C, B):
... def __init__(self):
... obj = super(D, self)
... print obj.__thisclass__
... print obj.__self_class__
... obj.__init__()
...
Now let us test it:
>>> d = D()
<class '__main__.D'>
<class '__main__.D'>
<class '__main__.C'>
<class '__main__.D'>
<class '__main__.B'>
<class '__main__.D'>
A
Ah Ah... see what's going on? When D.__init__ is first called, a super
object is instantiated. __thisclass__ and __self_class__ point to the
D class. But going up the call chain, the __thisclass__ reference is
updated *according* to the mro linearization. This way super always
knows where it is in the mro list and can call the right methods.
If you didn't understood, no problem. I'm not sure I understand it
myself fully!
Anyway, hope it helped some, with my best regards,
G. Rodrigues
More information about the Tutor
mailing list