The Python Oracle

Python - Confused about inheritance

--------------------------------------------------
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Switch On Looping

--

Chapters
00:00 Python - Confused About Inheritance
01:01 Accepted Answer Score 3
03:22 Thank you

--

Full question
https://stackoverflow.com/questions/4761...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #python3x

#avk47



ACCEPTED ANSWER

Score 3


First just to make it clear I would like to state that _abc is a class variable, not an instance variable so its address space is shared across parent and child class. Any change in the original _abc object affects all the class's _abc object. Read about class and instance variable (here at SO and here at DO)

To check that _abc share the same address space we can use python built-in id():

id() Return the “identity” of an object. This is an integer (or long integer) which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

To check this in the first round we can do:

In [33]: id(c._abc)
Out[33]: 4454841440 

In [34]: id(b._abc)
Out[34]: 4454841440

In [36]: id(A._abc)
Out[36]: 4454841440

In [38]: id(B._abc)
Out[38]: 4454841440

In [39]: id(C._abc)
Out[39]: 4454841440

All of them gives the same value for id(). In round 2, when you uncomment self._abc = kwargs see what happens to the value of id():

In [8]: id(b._abc)
Out[8]: 4585625712 # its different from A._abc and c._abc why?

In [9]: id(c._abc)
Out[9]: 4585627152 # same as A._abc

In [10]: id(A._abc)
Out[10]: 4585627152 # this is same as c._abc

Value of b._abc gets changed but the value of c._abc and A._abc remains the same. So, what is actually happening here?

When in round 1 you do:

# self._abc = kwargs                 
self._abc['a'] = kwargs['a']
self._abc['b'] = kwargs['b']
self._abc['Hello'] = 'World'

You are actually modifying the shared class variable _abc. Your code here is not creating a new self._abc object it is modifying the original self._abc class variable object but in round 2 when you do:

self._abc = kwargs

Here, the code is assigning kwargs, which is a dictionary with its own address space, to self._abc. self._abc becomes class B's instance variable and it is only available to the class B's objects.

To verify this point you can modify your class B to print id's as:

In [11]: class B(A):
    ...:
    ...:     def __init__(self,successor=None,**kwargs):
    ...:         self._successor = successor
    ...:         print(id(self._abc))
    ...:         print(id(kwargs))
    ...:         self._abc = kwargs
    ...:         print(id(self._abc))

In [12]: b = B(**list)
4585627152 # original self._abc id
4583538904 # kwargs object's id
4583538904 # New self._abc id

As you can see originally self._abc had address 4585627152 and kwargs had 4583538904 but after self._abc= kwargs self._abc's new id is 4583538904.