[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