Mutli-inheritance bug between python 2.7 and 3.7

  sonic0002        2019-05-16 08:33:52       2,852        1         

When we have run a py3.7 code under py2.x or a py2.x code under 3.x ,if a class do mutli-inheritance from 2 parent and the 2 parents also got inheritance from same parent, the different way to handle inheritance chain between python 2 and 3 will cause some running time bug:

Assume we got this sample program inheritTest.py :

# Purpose:     Test mutli-inheritance different between python2 and 3
# Author:      Yuancheng Liu
# Created:     2019/05/16
class A:
    def getVal(self):
        print("call A's getVal()")
    def setVal(self):
        print("call A's setVal()")

class B(A):
    def getVal(self):
        print("call B's getVal()")
    #def setVal(self):
    #    print("call B's setVal()")

class C(A):
    def getVal(self):
        print("call C's getVal()")
    def setVal(self):
        print("call C's setVal()")

class D(B, C):
    pass


import platform
print(platform.python_version())
obj = D()
obj.getVal()

The inheritance chain is like this:

No alt text provided for this image

If we run the program under python 2.7 the result is this:

Python 2.7.14 (v2.7.14:84471935ed, Sep 16 2017, 20:19:30) [MSC v.1500 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> 
====== RESTART: C:\Singtel\Programs\IOT\IOT\IOT\firmwSign\inhertTest.py ======
2.7.14
call B's getVal()
call A's setVal()
>>> 

But if we run the program under python3.7, the result shows:

PS C:\Singtel\Programs\IOT\IOT\IOT> & C:/Users/dcslyc/AppData/Local/Programs/Python/Python37-32/python.exe c:/Singtel/Programs/IOT/IOT/IOT/firmwSign/inhertTest.py
3.7.3
call B's getVal()
call C's setVal()
call C's setVal()

The inheritance trace of python 2 and python 3 is:

No alt text provided for this image

The reason caused this is the different MRO algorithm between python 2 and three.

In python 2 when we do Mutli-inheritance[class D (B, C)], the inheritance trace is from left to right: B =>A=> C=>A to look for the method.

In python 3 when we do Mutli-inheritance[class D (B, C)], the inheritance trace is: get the header of the first direct inheritance then go through all the parent class to find the shortest sequence in the merged relation list:

inh[D(B ,C)] = D + merge[inh(B(A)) +inh(C(A))]

inh[D(B ,C)] = D + merge[B+merge(A(object)) +C+ merge(A(object)))]

inh[D(B ,C)] = D + merge[B + A=>object + C+ A=>object] O for object class

inh[D(B ,C)] = D + merge[B + AO + C+ AO] O for object class

inh[D(B ,C)] = D + [BAO + BC+ CAO] O for object class # use B as header to trace the shortest set then get BC (contents B and shortest in the list)

inh[D(B ,C)] = D + BC + [BAO + CAO]

So the C's setValue() method is called. So the program get different result when running under python 2 and 3. 

Note: This post is authorized to republish here by Yuancheng Liu, Systems Software Engineer at ZycraftUSV.PTE.LTD. Original post is here.

PYTHON  PYTHON 3  INHERITANCE 

       

  RELATED


  1 COMMENT


Anonymous [Reply]@ 2019-05-16 09:24:00

Just inherit from object on Python 2 and you'll get the same behaviour. Next time read the documentation



  RANDOM FUN

Project Ara, Another of Google’s Speculation. This time for modular phones

Google is very adamant with the test of their new modular phones, nicknamed as Project Ara. The company is auspicious about the new concept where consumers can design their own phones by assembling parts from different manufacturers. The company is hopeful that there will be 20 to 30 interchangeable