欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程语言 > python >内容正文

python

pythonsuper多重继承_小白都能理解的Python多继承

发布时间:2025/4/5 python 106 豆豆
生活随笔 收集整理的这篇文章主要介绍了 pythonsuper多重继承_小白都能理解的Python多继承 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

前言

本文主要做科普用,在真实编程中不建议使用多重继承,或者少用多重继承,避免使代码难以理解。

方法解析顺序(MRO)

关于多重继承,比较重要的是它的方法解析顺序(可以理解为类的搜索顺序),即MRO。这个跟类是新式类还是经典类有关,因为两者的搜索算法不同。

在Python2及以前的版本,由任意内置类型派生出的类(只要一个内置类型位于类树的某个位置),都属于新式类;反之,不由任意内置类型派生出的类,则称之为经典类

在Python3以后,没有该区分,所有的类都派生自内置类型object,不管有没有显式继承object,都属于新式类。

对于经典类,多重继承的MRO是深度优先,即从下往上搜索;新式类的MRO是采用C3算法(不同情况下,可表现为广度优先,也可表现为深度优先)。

C3算法表现为深度优先的例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

# C3-深度优先(D -> B -> A -> C)

class A:

var = 'A var'

class B(A):

pass

class C:

var = 'C var'

class D(B, C):

pass

if __name__ == '__main__':

# [, , , , ]

print(D.mro())

# A var

print(D.var)

复制代码

C3算法表现为广度优先的例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

# C3-广度优先(D -> B -> C -> A)

class A:

var = 'A var'

class B(A):

pass

class C(A):

var = 'C var'

class D(B, C):

pass

if __name__ == '__main__':

# [, , , , ]

print(D.mro())

# C var

print(D.var)

复制代码

注:关于C3的详细算法本文不讨论,因为我也搞不懂(狗头保命)

菱形多重继承

其实菱形多重继承上面已经有例子了,就是C3算法表现为广度优先这个例子,画起图来是这样的:

菱形多重继承会导致的一个问题是A初始化了两次,如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

class A:

def say(self):

print("A say")

class B(A):

def say(self):

print("B say")

A.say(self)

class C(A):

def say(self):

print("C say")

A.say(self)

class D(B, C):

def say(self):

print("D say")

B.say(self)

C.say(self)

if __name__ == '__main__':

dd = D()

dd.say()

复制代码

如果只想调用一次A,可使用super方法:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

class A:

def say(self):

print("A say")

class B(A):

def say(self):

print("B say")

super().say()

class C(A):

def say(self):

print("C say")

super().say()

class D(B, C):

def say(self):

print("D say")

super().say()

if __name__ == '__main__':

print(D.mro())

dd = D()

dd.say()

复制代码

_init_ 与 super()

1.如果父类有init方法,子类没有,则子类默认继承父类的init方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

class A:

def __init__(self, a1, a2):

self.a1 = a1

self.a2 = a2

def say(self):

print("A say, a1: %s, a2: %s" % (self.a1, self.a2))

class B(A):

def say(self):

print("B say, a1: %s, a2: %s" % (self.a1, self.a2))

if __name__ == '__main__':

# 因为B继承了A的init方法,所以也要传入 a1,a2参数

bb = B("10", "100")

bb.say()

复制代码

2.如果父类有init方法,子类也有,可理解为子类重写了父类的init方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

class A:

def __init__(self, a1, a2):

self.a1 = a1

self.a2 = a2

def say(self):

print("A say, a1: %s, a2: %s" % (self.a1, self.a2))

class B(A):

def __init__(self, b1):

self.b1 = b1

def say(self):

print("B say, b1: %s" % self.b1)

if __name__ == '__main__':

# 此处B重写了A的init方法,所以只需要传入b1参数,也没有拥有a1,a2属性

bb = B("10")

bb.say()

复制代码

3.对于第二点,为了能使用或者扩展父类的行为,更常见的做法是在重写init方法的同时,显示调用父类的init方法(意味传的参数要变成3个)。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

# 三种写法

class A:

def __init__(self, a1, a2):

self.a1 = a1

self.a2 = a2

def say(self):

print("A say, a1: %s, a2: %s" % (self.a1, self.a2))

class B(A):

def __init__(self, b1, a1, a2):

# 第一种写法: Python2的写法

# super(B, self).__init__(a1, a2)

# 第二种写法(推荐):Python3的写法,与第一种等价

super().__init__(a1, a2)

# 第三种写法:与前两种等价,不过这种需要显示调用基类,而第二种不用

# A.__init__(self, a1, a2)

self.b1 = b1

def say(self):

print("B say, a1: %s, a2: %s, b1: %s" % (self.a1, self.a2, self.b1))

if __name__ == '__main__':

# 此处B重写了A的init方法,所以只需要传入b1参数,也没有拥有a1,a2属性

bb = B("10", "100", "1000")

bb.say()

复制代码

最后的提醒

注意 __init__ 方法不要写错,避免写成__ini__或者其他的,因为两个是在太像,出了问题很难排查(坑过两次)。

参考

python 多重继承的事

当心掉进Python多重继承里的坑

总结

以上是生活随笔为你收集整理的pythonsuper多重继承_小白都能理解的Python多继承的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。