首页 > 其他 > 详细

继承的优缺点

时间:2019-03-06 18:24:08      阅读:163      评论:0      收藏:0      [点我收藏+]

今天讨论两个话题

* 子类化内置类型的缺点

* 多重继承和方法解析顺序(__mro__)

许多人都对继承敬而远之。Java不支持多继承,并没有产生什么坏的影响,而C++对多继承的滥用上了很多人的心(笔者也是其中一位)。因此,今天就讨论一下多继承到底是怎么回事。

子类化内置类型很麻烦

直接子类化内置类型(如继承list、dict、str)容易出错,因为内置类型的方法通常会忽略用户覆盖的方法。因此不要子类化内置类型,用户应该继承collections模块中的类,UserDict、UserList、UserString等,这些类是python提供给用户用来扩展的。

多重继承和方法解析顺序

与继承尤其是多继承密切相关的另一个问题是:如果同级的父类有个同名方法或属性,那么python如何决定使用哪一个?

作为一个曾经的C++程序员,经常要面临这个问题。实际上,任何支持多继承的语言都要面临这种潜在的命名冲突,这种冲突由不相关的父类实现了同名的方法引起,这就是经典的”菱形问题“。

举例说明如下:

 1 class A:
 2     def ping(self):
 3         print("ping:", self)
 4 
 5 class B(A):
 6     def pong(self):
 7         print("pong:", self)
 8 
 9 class C(A):
10     def pong(self):
11         print("PONG:", self)
12 
13 class D(B, C):
14     def ping(self):
15         super(D, self).ping()
16         print(post-ping:, self)
17 
18     def pingpong(self):
19         self.ping()
20         print(1)
21         super(D, self).ping()
22         print(2)
23         self.pong()
24         print(3)
25         super(D, self).pong()
26         print(4)
27         C.pong(self)

类B、C继承类A,且都实现了pong方法,但是打印的内容不一样。

如果D的实例调用pong方法的话,调用的是C的还是B的呢?答案是B的pong方法。

类有一个名为__mro__的属性,它是个元组,python会按照__mro__的值按照方法解析出各个父类,知道object类为止。如果想调用父类的方法,推荐使用super()函数。你也可以使用类名.方法(self)的方式调用父类的方法,但是不推荐,如果想绕过方法解析顺序可以使用。

类的继承关系和__mro__解析顺序如下图:

技术分享图片

 1 d = D()
 2 d.ping()
 3 print("-------------------------------")
 4 d.pingpong()
 5 
 6 
 7 """
 8 运行结果
 9 ping: <__main__.D object at 0x00000000035F62E8>
10 post-ping: <__main__.D object at 0x00000000035F62E8>
11 -------------------------------
12 ping: <__main__.D object at 0x00000000035F62E8>
13 post-ping: <__main__.D object at 0x00000000035F62E8>
14 1
15 ping: <__main__.D object at 0x00000000035F62E8>
16 2
17 pong: <__main__.D object at 0x00000000035F62E8>
18 3
19 pong: <__main__.D object at 0x00000000035F62E8>
20 4
21 PONG: <__main__.D object at 0x00000000035F62E8>
22 """

方法解析顺序不仅跟继承关系有关,还跟子类中声明的父类顺序有关。如果把类的声明顺序改变,那方法解析顺序也会改变:

 1 class E(B, C):
 2     pass
 3 
 4 class F(C, B):
 5     pass
 6 
 7 print(E.__mro__)
 8 print(F.__mro__)
 9 
10 """
11 (<class ‘__main__.E‘>, <class ‘__main__.B‘>, <class ‘__main__.C‘>, <class ‘__main__.A‘>, <class ‘object‘>)
12 (<class ‘__main__.F‘>, <class ‘__main__.C‘>, <class ‘__main__.B‘>, <class ‘__main__.A‘>, <class ‘object‘>)
13 """

方法解析顺序依赖于C3算法。详见https://www.python.org/download/releases/2.3/mro/

GUI工具包Tkinter的继承关系图如下:

加入Text的声明顺序是:

class Text(YView, XView, Widget):

  ...

技术分享图片

那么方法解析顺序就应该是:

Text -> YView -> XView -> Widget -> Grid -> Place -> Pack -> BaseWidget -> Misc -> object

多重继承的应用

《设计模式:可复用面向对象软件的基础》中的适配器模式用的就是多重继承(但是其他22个设计模式都是用单继承,可见多重继承显然是不推荐使用)。

继承的优缺点

原文:https://www.cnblogs.com/forwardfeilds/p/10485022.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!