Mutli-inheritance bug between python 2.7 and 3.7

  sonic0002        2019-05-16 08:33:52       2,794        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.

INHERITANCE  PYTHON 3  PYTHON 

       

  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

What is VBA?

This is a conversation on Google product forum. Google engineers really don't know what is VBA? Or they just refuse to acknowledge the existence of VBA? The full conversation can be found at https://productforums.google.com/forum/m/#!topic/chrome/zY-8vP1lIys