day25---面向对象继承与多态
1. 面向对象的继承
-
定义:继承是一种创建新类的方式
-
种类:新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
-
方式:
-
单继承:所有的类默认都会继承'object'
-
多继承:继承多个类时,使用逗号分割,默认继承最左边的父类
-
-
__base__:只查看从左到右继承的第一个子类;如果没有继承,默认返回:<class 'object'>
class Biology:
pass
class Animal:
pass
class Cat(Biology):
pass
class Dog(Animal):
pass
class Monkey(Biology, Animal):
pass
print(Biology.__base__)
print(Animal.__base__)
print(Cat.__base__)
print(Dog.__base__)
print(Monkey.__base__)
>>>
<class 'object'>
<class 'object'>
<class '__main__.Biology'>
<class '__main__.Animal'>
<class '__main__.Biology'>
-
__bases__:查看所有继承的父类,返回元组格式;如果没有继承,默认返回:(<class 'object'>,)
class Biology:
pass
class Animal:
pass
class Cat(Biology):
pass
class Dog(Animal):
pass
class Monkey(Biology, Animal):
pass
print(Biology.__bases__)
print(Animal.__bases__)
print(Cat.__bases__)
print(Dog.__bases__)
print(Monkey.__bases__)
>>>
(<class 'object'>,)
(<class 'object'>,)
(<class '__main__.Biology'>,)
(<class '__main__.Animal'>,)
(<class '__main__.Biology'>, <class '__main__.Animal'>)
2. 类的说明
-
查看类的属性:
-
dir(类名):查出的是一个名字列表,里面包含这个类的所有方法
-
类名.__dict__:查出的是一个字典,key为属性名,value为属性值
-
-
特殊的类属性:
-
类名.__name__:类的名字,字符串类型
-
类名.__doc__:类的文档,字符串类型
-
类名.__base__:类的第一个父类
-
类名.__bases__:以元组的形式返回类的所有父类
-
类名.__dict__: 以字典的形式返回类的所有属性
-
类名.__module__:类所在的模块名,字符串类型
-
实例名.__class__:返回实例名所属的类名
-
3. 继承与抽象(先抽象后继承)
+ ##### 抽象(从具体到模糊的过程):即抽取类似或者说比较像的部分;抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类
+ ##### 继承(从模糊到具体的过程):是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构
4. 继承的派生
-
派生:子类在父类方法和属性的基础上产生了新的方法和属性
-
派生属性:在子类的__init__中使用父类的__init__的属性。调用父类的属性时,可以使用父类名.__init__;也可以使用super()方法,super()方法中的参数在类中使用可以省略
-
派生方法:在子类中增加父类中没有的方法
-
子类中有的方法,就使用子类的
-
父类中没有的方法,子类中有,会使用子类的
-
父类中有的方法,子类也有,会使用子类的
-
父类中有的方法,子类中没有,会使用父类的
-
-
父类中有的方法,子类也有,如果想坚持使用父类中的或父类子类都想用,需要使用:父类名.父类的方法名(子类的对象)
-
经典类(python2默认的面向对象类型):类名.方法名(子类对象名),类内类外调用方式一样
-
新式类(python3默认的面向对象类型):super(子类, 子类对象名).方法名(),如果在类中调用可以省略super()方法中的参数
class Life: def __init__(self, name, age): self.name = name self.age = age def eat(self): print('吃...') def drink(self): print('喝...') class Person(Life): def __init__(self, name, age, nation): Life.__init__(self, name, age) self.nation = nation def get_money(self): print('挣钱。。。') def eat(self): print('人吃饭。。。') class Dog(Life): def __init__(self, name, age, breed): super(Dog, self).__init__(name, age) self.breed = breed def watch_door(self): print('看门。。。') def drink(self): print('狗喝水。。。') yan = Person('岩哥', 25, '汉族') king = Dog('斑马', 2, '金毛') print(yan.name) print(king.age) print('-' * 20) print(yan.nation) print(king.breed) print('-' * 20) yan.get_money() king.watch_door() print('-' * 20) yan.eat() super(Person, yan).eat() king.eat() print('-' * 20) yan.drink() king.drink() super(Dog, king).drink() >>> 岩哥 2 -------------------- 汉族 金毛 -------------------- 挣钱。。。 看门。。。 -------------------- 人吃饭。。。 吃... 吃... -------------------- 喝... 狗喝水。。。 喝... -
5. 钻石继承
-
继承顺序
-
pyhton可以继承多个类,而其他语言只能继承一个类
-
python的类如果继承了多个类,寻找的方式有两种:
-
深度优先:当类是经典类时,多继承情况下会按照深度优先的方式查找
-
广度优先:当类是新式类时,多继承情况下会按照广度优先的方式查找
-
-
经典类和新式类从字面意思能看出是一个老的一个新的。新式类比经典类多了很多的功能,推荐使用新式类。在写法上,类或者父类都继承了Object类,就代表是新式类,反之是经典类。
# O1和O2都是经典类 class O1: pass class O2(O1): pass# N1和N2都是新式类 class N1(object): pass class N2(N1): pass -
-
继承原理
-
mro():以列表的形式返回当前类所有父类的查找顺序。mro()方法只有新式类才有,经典类没有
-
为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止
-
父类的MRO列表并遵循如下三条准则:
-
子类会先于父类被检查
-
多个父类会根据它们在列表中的顺序被检查
-
如果对下一个类存在两个合法的选择,优先选择第一个父类
-
-
-
钻石继承的验证(在python2中操作)
# 经典类(三层)的继承顺序
class D:
pass
class C(D):
pass
class B(D):
pass
class A(B, C):
pass
print(A.mro())
>>>
print(A.mro())
AttributeError: class A has no attribute 'mro'
# python2不支持mro()方法,正确的顺序是:A-->B-->D-->C
# 经典类(四层)的继承顺序
class F:
pass
class E(F):
pass
class D(F):
pass
class C(E):
pass
class B(D):
pass
class A(B, C):
pass
print(A.mro())
>>>
print(A.mro())
AttributeError: class A has no attribute 'mro'
# python2不支持mro()方法,正确的顺序是:A-->B-->D-->F-->C-->E
# 新式类(三层)的继承顺序
class D(object):
pass
class C(D):
pass
class B(D):
pass
class A(B, C):
pass
print(A.mro())
>>>
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <type 'object'>]
# 新式类(四层)的继承顺序
class F(object):
pass
class E(F):
pass
class D(F):
pass
class C(E):
pass
class B(D):
pass
class A(B, C):
pass
print(A.mro())
>>>
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class '__main__.F'>, <type 'object'>]
6. 抽象类与接口类
-
继承有两种用途:
-
继承基类的方法,并且做出自己的改变或者扩展(代码重用)
-
声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能
-
-
抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
-
如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性
-
抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性
-
抽象类是一个介于类和接口之间的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
-
多继承问题:
-
在继承抽象类的过程中,应该尽量避免多继承
-
在继承接口的时候,应该多继承接口
-
-
方法的实现:
-
在抽象类中,可以对一些抽象方法做出基础实现
-
在接口类中,任何方法都只是一种规范,具体的功能需要子类实现
-
-
依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该应该依赖细节;细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程
-
接口隔离原则:使用多个专门的接口,而不使用单一的总接口。即客户端不应该依赖那些不需要的接口
7. 多态
-
多态:多态指的是一类事物有多种形态;python自带多态功能
-
多态性:多态性是指在不考虑实例类型的情况下使用实例
-
鸭子类型:python崇尚鸭子类型

浙公网安备 33010602011771号