面向对象三大特性之继承
继承与__bases__
class Man(object): def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender Woman(object): gender m1 = Man("小明",18,male") w1 = Woman(小红female) # 使用 实例名.__class__ 可以看到实例对象属于的类 print(m1.__class__) <class '__main__.Man'> print(w1. <class '__main__.Woman'> class Woman(Man): 继承 Man, 拿到 Man 的所有方法与属性 pass m1 = Man( <class '__main__.Woman'> 使用 类名.__bases__ 可查看继承的父类 Ps: __base__ 返回类对象, __bases__ 返回元组,该元组每个索引上封装了一个类对象 print(Woman.__base__) __bases__) (<class '__main__.Man'>,) 经典类与新式类
==== Python2中的经典类 ==== B1: pass B2(B1): ==== Python2中的新式类 ==== F1(object): F2(F1): Ps:Python3中即使没有继承任何类,也都默认继承了object类。因此Python3中的所有类都是新式类。 派生方法覆写
F1(object): def show(self): print(F1.show) F2(F1): F2.show) f = F2() f.show() F2.show 单继承单继承的查找顺序
单继承查找注意事项
普通方法查找 A(object): ---A.show---) self.test() test(self): ---A.test--- B(A): ---B.test---) b1 = B() b1.show() ==== 执行结果 === """ ---A.show--- ---B.test--- """ ==== 步骤分析 === 1. 查找 b.__dict__ 试图找到show 失败 2. 查找 B.__dict__ 试图找到show 失败 3. 查找 A.__dict__ 试图找到show 成功!!找到实例绑定方法show() 将 实例化对象 b1 自动传入 # === 开始重新接着找 === 4. 查找 b.__dict__ 试图找到test 失败 5. 查找 B.__dict__ 试图找到test 成功!!找到实例绑定方法test() 将 实例化对象 b1 自动传入 """ 私有方法,隐藏方法查找 ) self.__test() (self): ---A.show--- ---A.test--- 1. 查找 b.__dict__ 试图找到show 失败 2. 查找 B.__dict__ 试图找到show 失败 3. 查找 A.__dict__ 试图找到show 成功!!找到实例绑定方法show() 将 实例化对象 b1 自动传入 # === 开始重新接着找 === 4. 查找 b.__dict__ 试图找到_A__test 失败 5. 查找 B.__dict__ 试图找到_A__test 失败 6. 查找 A.__dict__ 试图找到_A__test 成功!!找到实例绑定方法_A__test() 将 实例化对象 b1 自动传入 """ 多继承普通多继承与钻石多继承
普通多继承的查找顺序
---A--- B(object): ---B--- C(object): ---C--- D(A): ---D--- E(B): ---E--- F(C): ---F--- G(D,E,F): ---G---print(G.mro()) 继承查找链,Python2中无法使用。 [<class '__main__.G'>,<class '__main__.D'>,<class '__main__.A'>,<class '__main__.E'>,<class '__main__.B'>,<class '__main__.F'>,<class '__main__.C'>,<class 'object'>] 钻石多继承下的经典类查找顺序(深度优先)
-*- coding:utf-8 -*- 由于Python2中super方法并不支持经典类。也不支持mro方法,所以我就这样来进行验证了。 A: B(A): C(A): G(D): H(E,F,G): h1 = H() h1.show() ---A--- 钻石多继承下的新式类查找顺序(广度优先)
print(H.mro()) 继承查找链,Python2中无法使用 [<class '__main__.H'>,<class '__main__.G'>,<class 'object'>] __mro__方法介绍
super()方法 - 依赖__mro__super()的基本使用案例
Person(object): 人类""" Student(Person): 学生 height self.weight = weight super(Student,self).__init__(name,gender) 调用父类的方法。根据当前实例对象的类的mro列表的顺序进行查找 # super().__init__(height,weight) 尽管可以这样传参,但是我仍然推荐上面的传参方式。 get_msg(self): 姓名是:[{0}],年龄是:[{1}],性别是:[{2}],身高是:[{3}],体重是[{4}].format(self.name,self.age,self.gender,self.height,self.weight)) s1 = Student() s1.get_msg() 姓名是:[小明],年龄是:[18],性别是:[male],身高是:[178],体重是[128] print(s1.__dict__) {'height': 178,'weight': 128,'name': '小明','age': 18,'gender': 'male'} super()方法在多继承下使用的注意事项
show(self): super(A,self).show() 1.根据mro列表来找,此时是A,向后。找到B ") 3.打印 ---A--- ") 2.打印 ---B--- 返回 C(A,B): print(C.mro()) [<class '__main__.C'>,<class 'object'>] c1 = C() c1.show() ==== 执行结果 ==== [<class '__main__.C'>,<class 'object'>] ---B--- ---A--- """ Python2经典类使用super()
==== 不添加 __metaclass__ = type ,经典类使用super()会抛出异常 ==== Traceback (most recent call last): File "C:/Users/Administrator/PycharmProjects/learn/logging?????.py",line 44,in <module> c1.show() File "C:/Users/Administrator/PycharmProjects/learn/logging?????.py",line 31,in show super(A,self).show() # 1.根据mro列表来找,此时是A,向后。找到B TypeError: super() argument 1 must be type,not classobj """ __metaclass__ = type Python2中的经典类查找顺序变为新式类的查找顺序。 如不添加则无法使用super方法 """ 直接调用某类中的方法 - 不依赖mro直接调用的基本使用案例==== 可以看到 A 和 B 之间并没有任何关系,我们依旧可以调用其中的方法 ==== show(self): B.show(self) 由于是类来调用方法,所以我们需要手动为其传入self参数。即手动传入当前实例化对象a1 print(A.mro()) [<class '__main__.A'>,1)"> a1 = A() a1.show() [<class '__main__.A'>,1)">""" 解决继承关系混乱:Mixins机制讲解
一个子类可以同时继承多个父类,这样的设计常被人诟病,一来它有可能导致可恶的菱形问题,二来在人的世界观里继承应该是个” 答案是有,我们还是拿交通工具来举例子: 民航飞机、直升飞机、轿车都是一个(“ class Vehicle: 交通工具 fly(self): ''' 飞行功能相应的代码 ''' I am flyingclass CivilAircraft(Vehicle): 民航飞机 pass class Helicopter(Vehicle): 直升飞机 class Car(Vehicle): 汽车并不会飞,但按照上述继承关系,汽车也能飞了 pass Python提供了 FlyableMixin: class CivilAircraft(FlyableMixin,Vehicle): class Helicopter(FlyableMixin,1)"> 汽车 pass 可以看到,上面的 使用
Displayer: display(self,message): print(message) LoggerMixin: def log(self,message,filename='logfile.txt'): with open(filename,a) as fh: fh.write(message) super的用法请参考下一小节 self.log(message) MySubClass(LoggerMixin,Displayer): log(self,message): super().log(message,filename=subclasslog.txt) obj = MySubClass() obj.display(This string will be shown and logged in subclasslog.txt 属性查找的发起者是obj,所以会参照类MySubClass的MRO来检索属性[<class '__main__.MySubClass'>,<class '__main__.LoggerMixin'>,<class '__main__.Displayer'>,<class 'object'>] 1、首先会去对象obj的类MySubClass找方法display,没有则去类LoggerMixin中找,找到开始执行代码 2、执行LoggerMixin的第一行代码:执行super().display(message),参照MySubClass.mro(),super会去下一个类即类Displayer中找,找到display,开始执行代码,打印消息"This string will be shown and logged in subclasslog.txt" 3、执行LoggerMixin的第二行代码:self.log(message),self是对象obj,即obj.log(message),属性查找的发起者为obj,所以会按照其类MySubClass.mro(),即MySubClass->LoggerMixin->Displayer->object的顺序查找,在MySubClass中找到方法log,开始执行super().log(message,filename='subclasslog.txt'),super会按照MySubClass.mro()查找下一个类,在类LoggerMixin中找到log方法开始执行,最终将日志写入文件subclasslog.txt 扩展:抽象基类的使用
? |