流畅的python——12 继承的优缺点

十二、继承的优缺点

子类化内置类型很麻烦

内置类型(使用 C 语言编写)不会调用用户定义的类覆盖的特殊方法。

至于内置类型的子类覆盖的方法会不会隐式调用,CPython 没有制定官方规则。基本上,内置类型的方法不会调用子类覆盖的方法。例如,dict 的子类覆盖的 __getitem__() 方法不会被内置类型的 get() 方法调用。

__setitem__ __getitem__ 方法:只有实例化子类对象,[] 运算符覆盖会生效

直接子类化内置类型(如 dict、list 或 str)容易出错,因为内置类型的方法通常会忽略用户覆盖的方法。不要子类化内置类型,用户自己定义的类应该继承 collections 模块(http://docs.python.org/3/library/collections.html)中的类,例如 UserDict、UserList 和 UserString,这些类做了特殊设计,因此易于扩展。

如果不子类化 dict,而是子类化 collections.UserDict,问题便迎刃而解了。

了让实验版通过原始版的测试组件,还要实现 __init__、get 和 update 方法,因为继承自 dict 的版本拒绝与覆盖的 __missing____contains____setitem__ 方法合作。

多重继承和方法解析顺序

任何实现多重继承的语言都要处理潜在的命名冲突,这种冲突由不相关的祖先类实现同名方法引起。这种冲突称为“菱形问题”。

(左)说明菱形问题UML 类图;(右)虚线箭头是示例 12-4 使用的方法解析顺序

In [2]: class A:
   ...:     def pint(self):
   ...:         print('ping:',self)
   ...:

In [7]: class C(A):
   ...:     def pont(self):
   ...:         print('pontCCC:',self)
   ...:

In [8]: class B(A):
   ...:     def pont(self):
   ...:         print('pontBBB:',self)
   ...:

In [6]: class D(B,C):
   ...:     def pint(self):
   ...:         super().pint()
   ...:         print('post-pint:', self)
   ...:     def pintpont(self):
   ...:         self.pint()
   ...:         super().pint()
   ...:         self.pont()
   ...:         super().pont()
   ...:         C.pont(self)
   ...:

In [12]: d = D()

In [13]: d.pont()
pontBBB: <__main__.D object at 0x000001E89548D7F0>

In [14]: C.pont(d)  # 显式调用
pontCCC: <__main__.D object at 0x000001E89548D7F0>

In [15]: d.pint()
ping: <__main__.D object at 0x000001E89548D7F0>
post-pint: <__main__.D object at 0x000001E89548D7F0>

In [17]: D.__mro__  # 查找属性和方法 顺序 
# 按照方法解析顺序列出各个超类,从当前类一直向上,直到 object 类。
Out[17]: (__main__.D, __main__.B, __main__.C, __main__.A, object)

注意,直接在类上调用实例方法时,必须显式传入 self 参数,因为这样访问的是未绑定方法(unbound method)。

方法解析顺序不仅考虑继承图,还考虑子类声明中列出超类的顺序。也就是说,如果在 diamond.py 文件(见示例 12-4)中把 D 类声明为 class D(C, B):,那么 D 类的__mro__ 属性就会不一样:先搜索 C 类,再搜索 B 类。

处理多重继承

……我们需要一种更好的、全新的继承理论(目前仍是如此)。例如,继承和实例化(一种继承方式)混淆了语用(比如为了节省空间而重构代码)和语义(用途太多了,比如特殊化、普遍化、形态,等等)。

​ ——Alan Kay

​ “The Early History of Smalltalk”

如 Alan Kay 所言,继承有很多用途,而多重继承增加了可选方案和复杂度。使用多重继承容易得出令人费解和脆弱的设计。我们还没有完整的理论,下面是避免把类图搅乱的一些建议。

多重继承,组合模糊,混入类

posted @ 2021-11-04 15:02  pythoner_wl  阅读(111)  评论(0编辑  收藏  举报