b站学习视频:https://www.bilibili.com/video/BV1M54y1d7UB?p=1
北理嵩天老师python课程笔记
- 封装:属性和方法的抽象,用数据和操作数据的方法来形成对象逻辑
- 继承:代码复用的高级抽象,用对象之间的继承关系来形成代码复用
- 多态:方法灵活性的抽象,让对象的操作更加灵活,更多复用代码
封装:对类的变量、函数进行定义、隔离以及保护,形成一个类对外可操作变量的函数的接口。多态是OOP的一个传统概念,Python天然支持多态,不需要特殊语法。
类对象 VS. 实例对象
类对象:Class Object,维护每个python类基本信息的数据结构
实例对象:Instance Object,Python类实例后产生的对象,简称:对象
这是一组概念,类对象全局只有一个,实例对象可以生成多个。
类的名字:建议采用大写单词的组合
类描述:在类定义后首行,以独立字符串形式定义
定义后通过<类名>._doc_属性来访问
- 类定义完成后,默认生成一个类对象
- 每个类唯一对应一个类对象,用于存储整个类的基本信息
- 类对象是type类的实例,表达为type类型。
**注意:类对象中直接包含的语句会被执行,因此,一般不在类定义中直接包含语句。
**
类的构造函数:
- 类的构造函数用于从类创建实例对象的过程
- 类的构造函数为实例对象创建提供了参数输入方式
- 类的构造函数为实例属性的定义和赋值提供了支持
python使用预定义的__init__()作为构造函数
使用说明:
参数:第一个参数约定是self,表示类实例自身,其他参数是实例参数
函数名:python解释器内部定义,由双下划线开始和技术
返回值:构造函数没有返回值,或返回None,否则产生TypeError异常。
方法是类内部定义的函数
- 实例方法:实例对象的方法,由各实例对象独享,最常用的形式
- 类方法:类对象的方法,由所有实例对象共享
- 自由方法:类中一个普通函数,由类所在命名空间管理,类对象独享
- 静态方法:类中一个普通函数,由类对象和实例对象共享
- 保留方法:由双下划线开始和结束的方法,保留使用
类方法:
自由方法:
静态方法:
析构函数:
class DemoClass:
count = 0 #公开类属性
__count1 = 0 #私有类属性
def __init__(self.name): #实例方法
self.name = name
DemoClass.count +=1
@classmethod #类方法
def getchrCount(cls):
s ='零一二三四五六七八九十'
return s[DemoClass.count]
@classmethod #用类方法访问私有属性
def getCount1(cls):
return DemoClass.__count
def foo(): #自由方法
DemoClass.count *=100
return DemoClass.count
@staticmethod #静态方法
def foo():
DemoClass.count *=100
return DemoClass.count
def __len__(self): #保留方法
return len(self.name)
def __del__(self): #析构函数
print("再见",self.name)
解释:在dc2=dc1这条语句中又创建了一个指向对象的指针,换句话说,当前对象的引用为2,del dc1只是删除了一个引用,并没有删除对象的全部引用,所以析构函数不会执行,只会在程序退出时默认要销毁dc2,所以才会执行。(在删除对象前,python解释器会检查引用次数)
sys.getrefcount(<对象名>)获得对象的引用次数
封装Encapsulation:
用类方法访问私有属性可以对这个访问过程进行一定的控制,比如限制访问次数等。这就是用唯一接口去访问私有属性的好处。
class DemoClass
def __init__(self,name)
self.__name=name
def getName(self)
return self.__name
dc1= DemoClass("老王")
dc2= DemoClass("老李")
print(dc1._DemoClass__name)
这段代码会正常输出:老王。原因是,实际上Python设计逻辑不明确支持私有,双下划线方法只是一种转换约定,转换后,类内原有名字发生了变化,这是一种形式上的私有
java or C++…是有专门的方式定义私有属性的,但是python没有。
仅用<类名>访问的保留属性
保留属性 | 描述 |
---|---|
__name __ | 类的名称 |
__qualname__ | 以.分割从模块全局命名空间开始的类名称 |
__bases__ | 类所继承的基类名称 |
<类>/<对象>.__dict__ | 包含类成员/对象成员信息的字典,key是属性和方法名称,value是地址 |
__class__ | 对象所对应的类信息 |
__doc__ | 类描述,写在类定义的首行字符串,不能继承 |
__module__ | 类所在模块的名称 |
继承Inheritance:代码复用的高级抽象
object类是python所有类的基类(最基础的类是object,最基础的类型是type)
函数/保留字 | 描述 |
---|---|
id(x) | 返回x的标识,Cpython用内存地址表示 |
x is y | 判断x和y的标识是否相等,返回True/False,不判断值 |
重载:派生类对基类属性或方法的再定义
增量重载:派生类扩展定义与基类相同名称的方法
super().<基类方法名>(<参数列表>)
class<类名>(<基类名1>,<基类名2>,…,<基类名N>):
从左到右的顺寻暗含了优先级大小,并且是深度优先规则,意思是从基类1一直找到object如果都没有要找的属性/方法,才会从基类2开始。
运算重载的限制:
.__neg__(self) #取负
.__pos__(self) #取正
.__abs__(self) #取绝对值
.__invert__(self) #取反
.__add__(self,other) #加法
.__sub__(self,other) #减法
.__mul__(self,other) #乘法
.__truediv__(self,other) #除法
.__floordvi__(self,other) #整数除
.__mod(self,other)__ #模
.__divmod__(self.other) #对象除模
.__pow__(self,other) #幂的运算
.__lshift__(self,other) #左移
.__rshift__(self,other) #右移
.__lt/le/eq/ne/gt/ge__(self,other) #两个比较操作的运算重载< <= == != > >=
参数类型的多态:一个方法能够处理多个类型的能力
参数形式的多态:一个方法能够接受多个参数的能力
多态是OOP的一个传统概念,Python天然支持多态,不需要特殊语法
命名空间Namespace:从名字到对象的一种映射
比如一个人的年龄不可能是负数,但你给这个属性赋值为负时,并不能检测异常值,这就是个问题,如何为属性增加异常检测。
@property:类的特性装饰器
异常Exception也是一种python类
名称修饰Name Mangling:类中名称的变换约定
_x:单下划线开头的名称修饰
x_:单下划线结尾的名称修饰
__x:双下划线开头的名称修饰
__x__:双下划线开头和结尾的名称修饰
_:单下划线
python最小空类的作用: