标签:ons 绕过 spl lan 实例化 pos int 多重 org
本章探讨继承和子类化,重点是说明对 Python 而言尤为重要的两个细节:
在 Python 2.2 之前,内置类型(如 list 或 dict)不能子类化。在 Python 2.2 之后,内置类型可以子类化了,但是有个重要的注意事项: 内置类型(使用 C 语言编写)不会调用用户定义的类覆盖的特殊方法。
原生类型的这种行为违背了面向对象编程的一个基本原则:始终应该从 实例(self)所属的类开始搜索方法,即使在超类实现的类中调用也是 如此。在这种糟糕的局面中,__missing__ 方法(参见 3.4.2 节)却能 按预期方式工作,不过这只是特例。
不只实例内部的调用有这个问题(self.get() 不调用 self.getitem()),内置类型的方法调用的其他类的方法,如果 被覆盖了,也不会被调用。
class DoppelDict(dict):
def __setitem__(self, key, value):
super().__setitem__(key, [value] * 2)
dd = DoppelDict(one=1)
dd
{‘one‘: 1}
上面的init方法并没有使用我们的setitem()方法
dd[‘two‘] = 2
dd
{‘one‘: 1, ‘two‘: [2, 2]}
dd.update(three=3)
dd
{‘one‘: 1, ‘two‘: [2, 2], ‘three‘: 3}
继承自 dict 的 update 方法也不使用我们覆盖的 setitem 方 法:‘three‘ 的值没有重复。
class AnswerDict(dict):
def __getitem__(self, item):
return 42
ad = AnswerDict(a=‘foo‘)
ad[‘a‘] # 这里调用的子类方法
42
ac = {‘b‘:‘233‘}
ac.update(ad)
ac
{‘b‘: ‘233‘, ‘a‘: ‘foo‘}
d 是 dict 的实例,使用 ad 中的值更新 d。
dict.update 方法忽略了 AnswerDict.__getitem__ 方法。
直接子类化内置类型(如 dict、list 或 str)容易出错, 因为内置类型的方法通常会忽略用户覆盖的方法。不要子类化内置 类型,用户自己定义的类应该继承 collections 模块 (http://docs.python.org/3/library/collections.html)中的类,例如 UserDict、UserList 和 UserString,这些类做了特殊设计,因 此易于扩展。
这种冲突称为“菱形问题”:python的方法是逐层向上、从左到右依次查找方法来进行解析。
在 C++ 中,程序员必须使用类名限定方法调用来避免这种歧义。
如下:
void Derived::display(){
BaseA::show(); //调用BaseA类的show()函数
BaseB::show(); //调用BaseB类的show()函数
cout<<"m_e = "<<m_e<<endl;
}
在 Python 3 中,这种方式变得更容易了,如示例 12-4 中 D 类的 pingpong 方法所示。4 然而,有时可能需要绕过方法解析顺序,直接 调用某个超类的方法——这样做有时更方便。例如,D.ping 方法可以 这样写:
def ping(self):
A.ping(self) # 而不是super().ping()
print(‘post-ping:‘, self)
《设计模式:可复用面向对象软件的基础》 一书中的适配器模式用的就是多重继承,因此使用多重继承肯定没有错 (那本书中的其他 22 个设计模式都使用单继承,因此多重继承显然不 是灵丹妙药)。
在 Python 标准库中,最常使用多重继承的是 collections.abc 包。
def print_mro(x):
return x.__mro__
import tkinter
print_mro(tkinter.Toplevel)
(tkinter.Toplevel, tkinter.BaseWidget, tkinter.Misc, tkinter.Wm, object)
使用多重继承时,一定要明确一开始为什么创建子类。主要原因可 能有:
现代的 Python 中,如果类的作用是定义接口,应该明确把它定义为 抽象基类。Python 3.4 及以上的版本中,我们要创建 abc.ABC 或其 他抽象基类的子类(如果想支持较旧的 Python 版本,参见 11.7.1 节)。
如果一个类的作用是为多个不相关的子类提供方法实现,从而实现 重用,但不体现“是什么”关系,应该把那个类明确地定义为混入类 (mixin class)。从概念上讲,混入不定义新类型,只是打包方 法,便于重用。混入类绝对不能实例化,而且具体类不能只继承混 入类。混入类应该提供某方面的特定行为,只实现少量关系非常紧 密的方法。
具体类可以没有,或最多只有一个具体超类。
如果抽象基类或混入的组合对客户代码非常有用,那就提供一个 类,使用易于理解的方式把它们结合起来。Grady Booch 把这种类 称为聚合类(aggregate class)。
有道理
《Fluent Python》CH.12_面向对象_继承的优缺点 (菱形继承问题、不靠谱的内置类型的继承、不要使用多重继承)
标签:ons 绕过 spl lan 实例化 pos int 多重 org
原文地址:https://www.cnblogs.com/zhazhaacmer/p/14454290.html