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:
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:
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.
Just inherit from object on Python 2 and you'll get the same behaviour. Next time read the documentation