本文记录的是:python--面向对象特征、封装、多态、鸭子类型、类的约束、继承、多继承、mro、super、类的空间问题、类与类的关系
面向对象特征:
- 减少代码的从重用性。
- 增强代码的可读性
何为类:
就是具有相同属性和功能的一类事物 ,如 人类,动物类,鸟类
何为对象:
就是类的具体体现,如:一个黄头发,白皮肤的欧洲人。 具体到一个个体
面向对象编程的优点:
- 是一类相似功能函数的集合,使你的代码更清晰化,更合理化
- 面向对象,要拥有上帝的视角看问题,类其实就是一个公共模板,对象就是从具体的模板实例化出来
类的结构:
class 类名(首字母大写):
静态字段或静态属性
属性名 = 共有属性值
方法或函数,动态属性
从类名操作静态属性:
查看类中的所有内容: 类名.__dict__ 该方式只能查看不能进行其他操作
查看类中的属性 : 类名. 属性名 该方式可以进行增删改查操作,但是他无法一次性显示全部的属性
从类名操作动态方法:
除静态方法,类方法之外,一般不会通过类名操作一个类中的方法
调用类中方法 : 类名. 方法名
类名加上(),就是要给实例化的过程,这样就会实例化一个对象
实例化过程简单的三步:
- 在内存里开辟一个对象空间,此时的对象空间中拥有一个指针,指向类
- 会自动执行__init__() 方法,会将 对象空间 自动赋值给 第一个参数 self
- 通过self,进行对对象空间中进行封装属性的操作
- 实例化过程完毕
对象操作对象空间属性:
- 对象查询对象中所有属性:对象.__dict__
- 对象通过万能的点操作对象中的单个属性, 进行增删改查
- 对象可以通过点去查看类中的属性,但是不可能增加,修改,删除类中的属性,
- 对象可以通过万能的点进行调用类中的方法,
总结一句话说。。。当用类名去调用方法时,此时的self只是一个位置参数。 当用对象名去调用方法时,self才是对象本身,由Python解析器帮助自动传入
对于类的空间问题:
哪里都可以添加对象属性,哪里都已添加类的属性
对象可以寻找到对象属性,以及类属性,但是类只能寻找到类属性
对象查找属性的顺序:先从对象空间找 --——》 类空间 ——--》 父类空间找
类名查找属性的顺序:先从本类空间找 --——》 父类空间找
类与类之间的关系:
依赖关系:在方法参数中传入其他对象
关联关系,组合关系,聚合关系:将别的对象封装为该对象的一个属性
class A:
def __init__(self,name):
self.name = name
def func(self,B):
self.B = B
class B:
def __init__(self,name):
self.name = name
a =A("demo")
b =B("demo_B")
a.func(b)
print(a.B.name) #输出结果 是 : demo_B
实现关系,继承关系
继承:
继承的特点:
- 增加了类的耦合性
- 减少了代码的重复
- 使得代码更加规范化,合理化
子类可以调用父类的除私有方法以外的所有方法。以及所有的静态属性
通过子类调用父类的三种方式:
- 父类名 . 方法名(参数——需要自己手动传 self)
- super(子类名,self) . 方法名(参数——self由解释器自动传入)
- super() . 方法名(参数——self由解释器自动传入) 推荐使用
多继承 保留
在Python2x版本中存在两种类:
一种是经典类,在Python2.2之前,一直使用的是经典类,
一种是新式类,在Python2,2之后出现了新式类,新式类的特点是基类的根是object类,需要手动继承
在Python3.x版本中只有一个类:
都是新式类,如果基类谁都不继承
经典类的多继承:
从左到右,一步走到底
新式类的多继承:
mro序列
MRO通用计算公式为:
mro(Child(Base1,Base2)) = [Child] + merge( mro(Base1) , mro(Base2) , [Base1 , Base2])
或者:
super 认识:
super 执行顺序其实是 按照 mro() 的顺序 查找
如果在真实的项目中只用 类名 点 mro() 就可以直接查看到 真实的 mro 顺序
封装:
借鉴JAVA的封装
多态:
因为Python 中设定方法参数时并没有设定类型,所以在Python中处处时多态
鸭子类型:
多个类中存在方法名相同的方法 就互成为鸭子类型
类的约束:
强制指定子类继承父类并且必须重写父类的方法
第一种模式
class A:
def fun(self):
raise TypeError("错误提示信息") #强制要求子类重写该方法
class B(A):
def fun(self): #如果没有重写该方法,则下方调用时会抛出错误
pass
b = B() #此时并不会报错
b.fun() #如果子类中没有重写该方法,则会抛出父类方法中提示的错误信息
第二种模式
#借用java中的抽象类,必须重写方法
from abc import ABCMeta,abstractmethod
class A(metaclass = ABCMeta):
@abstractmethod
def fun(self):
print("必须重写")
class B(A):
def fun(self): #如果没有重写父类中的这个方法,则会在实例化的过程中就直接报错
print("重写了该方法")
b = B() #如果子类没有重写父类的这个方法,则在子类实例化的过程中就会抛出错误
b.fun()