新/旧式类多重继承搜索调用顺序的区别

在多重继承当中,派生的类中,表面上看基类排列的顺序不同,会导致输出不同,当然实质上是调用的类方法不同,更实质原因是搜索方法的方式不同

__author__ = 'LiHui'

class MyBook(object):
    def __init__(self):
        print 'MyBook __init__'
    def foo(self):
        print 'MyBook foo'

class MyCook(object):
    def __init__(self):
        print 'MyCook __init__'
    def foo(self):
        print 'MyCook foo'

class MyCookBook(MyBook, MyCook):
    def __init__(self):
        print 'MyCookBook __init__'

class MyStoryBook(MyCook, MyBook):
    def __init__(self):
        print 'MyStoryBook __init__'

if __name__ == '__main__':
    cookbook = MyCookBook()
    cookbook.foo()
    storybook = MyStoryBook()
    storybook.foo()

这里输出结果,很简单

MyCookBook __init__
MyBook foo
MyStoryBook __init__
MyCook foo

cookbook和storybook调用foo方法时,分别搜索到了基类MyBook和MyCook里的foo方法,从而打印信息,这个例子比较easy

下面这个改进版,信息量就比较大了,注意这里class都是继承object,为新式类

__author__ = 'LiHui'

class MyBook(object):
    def __init__(self):
        print 'MyBook __init__'
    def foo(self):
        print 'MyBook foo'

class MyCook(object):
    def __init__(self):
        print 'MyCook __init__'
    def fun(self):
        print 'MyCook fun'

class MyCookBook(MyBook, MyCook):
    def __init__(self):
        print 'MyCookBook __init__'

class MyStoryBook(MyBook, MyCook):
    def __init__(self):
        print 'MyStoryBook __init__'
    def fun(self):
        print 'MyStoryBook fun'

class MyLastBook(MyCookBook, MyStoryBook):
    pass

if __name__ == '__main__':
    lastbook = MyLastBook()
    lastbook.foo()
    lastbook.fun()

输出结果为:

MyCookBook __init__
MyBook foo
MyStoryBook fun

1:打印了MyCookBook __init__,原因是MyLastBook里面没有__init__,因此继承其第一个基类MyCookBook的时候,会调用基类的__init__方法,因此会打印这一行,而MyStoryBook的却没有打印,说明根本就调用这个类的构造器;而后面的MyBook和MyCook却没有打印,是子类MyCookBook的__init__将他们的给覆盖掉了

2:搜索调用顺序

MyLastBook =》 MyCookBook =》 MyBook =》 foo

MyLastBook =》 MyStoryBook =》 fun

也就是说这种情况下,搜索的方式是广度优先的原则,然后再从左到右搜索其它基类,依旧广度优先;更直接一点就是,派生出来的子类,先搜索参数里第一个基类,然后第二个基类,所有基类搜索完毕没找到,再搜索第一个基类的第一个基类,接着第一个基类的第二个基类,如此循环

 

下面会将基类的object给去掉,这是一种旧式类定义

__author__ = 'LiHui'

class MyBook():
    def __init__(self):
        print 'MyBook __init__'
    def foo(self):
        print 'MyBook foo'

class MyCook():
    def __init__(self):
        print 'MyCook __init__'
    def fun(self):
        print 'MyCook fun'

class MyCookBook(MyBook, MyCook):
    def __init__(self):
        print 'MyCookBook __init__'

class MyStoryBook(MyBook, MyCook):
    def __init__(self):
        print 'MyStoryBook __init__'
    def fun(self):
        print 'MyStoryBook fun'

class MyLastBook(MyCookBook, MyStoryBook):
    pass

if __name__ == '__main__':
    lastbook = MyLastBook()
    lastbook.foo()
    lastbook.fun()

除了去掉了object之外,没有任何改变

MyCookBook __init__
MyBook foo
MyCook fun

这里的搜索顺序变成了:

MyLastBook =》 MyCookBook =》 MyBook =》 foo

MyLastBook =》 MyCookBook =》 MyBook =》 MyCook =》 fun

也就是说这种情况下,搜索的方式是深度优先的原则,然后再从左到右搜索其它基类,依旧深度优先;更直接一点就是,派生出来的子类,先搜索参数里第一个基类,然后深度遍历完第一个基类,接着搜索第二个基类,深度遍历完,直到搜索完所有基类,以找到对应的方法

 

这就是旧式类和新式类的区别,遍历搜索方式不同,旧式是深度优先,而新式类是广度优先

发表回复