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

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

  • 相关阅读:
    力扣(LeetCode)922. 按奇偶排序数组 II
    力扣(LeetCode)1002. 查找常用字符
    力扣(LeetCode)15. 三数之和
    Java == 和 equals 区别
    力扣(LeetCode)125. 验证回文串
    力扣(LeetCode) 905. 按奇偶排序数组
    力扣(LeetCode)832. 翻转图像
    力扣(LeetCode) 771. 宝石与石头
    Sticks
    荷马史诗
  • 原文地址:https://www.cnblogs.com/pythonwl/p/15508237.html
Copyright © 2020-2023  润新知