17.面向对象进阶
面向对象进阶
类的继承
-
什么是继承:
- 继承是一种创建新类的方式,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类。
- 继承的特性是:子类会遗传父类的属性
-
为什么用继承:
可以减少代码的冗余,解决代码重写问题. -
继承的语法: # class 类名(父类名): pass
-
python中查看对象所继承的类,使用
.__bases__
方法- 在Python3中如果一个类没有继承任何类,则默认继承object类
- 在Python2中如果一个类没有继承任何类,不会继承object类
-
有继承关系下查找属性的顺序:
- 优先找自身,自身没有找父类
- 父类没有找父类的父类
- 一直找到最顶级的父类,如果还没有报错
类的派生
派生: 子类可以添加自己新的属性或者在自己这里重新定义父类已有的一些属性,需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准.
类的组合
通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,调用的是自身的属性和方法.
用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,还是得通过组合的类来调用它内部的属性和方法.
菱形继承问题
-
类可分为经典类和新式类
- 经典类:
- 没有继承object的类以及该类的子类,都是经典类
- 只有Python2中才有经典类
- 新式类:
- 继承了object的类以及该类的子类,都是新式类
- Python3中所有的类都是新式类
- 经典类:
-
当继承为菱形继承的时候,经典类和新式类搜索某一个属性的顺序会不一样
- 在新式类中:当遇到菱形继承时,会以广度优先查找
- 在经典类中:当遇到菱形继承时,会以深度优先查找
-
python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序的MRO列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,可以通过
.__mro__
的方法查看.
子类中调用父类的方法
- 在子类中通过父类名.父类方法(self)的方式调用,把这种调用方式当作对普通函数方法的调用
- super()/super(类名,self)的方式
- 当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super(),并只调用它一次,那么最终会遍历完整个MRO列表,每个方法也只会被调用一次.
多态与多态性
多态:对象的多种状态 - 父类对象的具有多种子类对象的状态
多态性:向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方法).
在python中通过在父类中引入abc模块的abc.abstractmethod
装饰器定义为抽象父类,通过在子类中重写来具体像可以实现多态性.
鸭子类型
- 规定有什么属性及什么方法的类的类型叫鸭子类型
- 能提供出规定的属性与方法的对象就是鸭子
- 也就是像鸭子就是鸭子
类的封装
比如字典里储存数据,相当于对数据的封装, 而函数封装了方法,从广义上说类的定义本身就是封装的体现,类封装了属性和方法,我们可以把它理解为第一层面的封装.
第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。
对于这一层面的封装(隐藏),我们需要在类中定义一个函数(接口函数)在它内部访问被隐藏的属性,然后外部就可以使用了
虽然我们也可以通过_类名__属性名来使用隐藏属性,但似乎不符合规范
@property装饰器
在类中有些方法所得到的结果更像是一种属性,我们可以使用@property装饰器置于这些方法之上,将其伪装成一个数据属性,在使用时可以类似于使用属性的方式不用加括号而直接使用
定义时,在实例方法上添加 @property 装饰器时,注意实例方法只能有一个self参数
除了@property装饰器,还介绍了@setter和@deleter两种装饰器,@setter在修改实例对象方法时会触发,而@deleter是在删除实例对象方法时触发.
类与对象的绑定方法和非绑定方法
- 在类中没有被任何装饰器修饰的方法就是 绑定到对象的方法,这类方法专门为对象定制。
- 类中使用 @classmethod 修饰的方法就是绑定到类的方法。这类方法专门为类定制。通过类名调用绑定到类的方法时,会将类本身当做参数传给类方法的第一个参数
- 在类内部使用 @staticmethod 修饰的方法即为非绑定方法,这类方法和普通定义的函数没有区别,不与类或对象绑定,谁都可以调用,且没有自动传值的效果。