类方法
- 类方法 VS 静态方法 VS 实例方法
- 通常都在类代码块内定义
- 类方法和实例方法 都有宿主
- 类方法的使用类对象
cls
作为第一个参数, 实例方法则是 实例对象self
- 实例的可见范围更广,宿主可以传递各自相关信息,显然实例传递的信息量更大
- 类方法定义 使用装饰器
@classmethod
- 类方法的使用类对象
- 静态方法
- 无需宿主参数
self,cls
定义 - 方法体中不能使用类或实例的任何属性和方法
- 定义 通常使用装饰器
@staticmethod
- 静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系
- 静态方法是类中的函数,不需要实例,它仅仅托管于某个类的名称空间中,便于使用和维护
- 无需宿主参数
- 实例方法
- 只能由实例对象调用
- 范围大小
- python类静态方法借用类的命名空间,在类内已完成,仅仅只是类内函数
- 类方法则可以使用类对象级别的信息,一般涉及到类的创建,生命周期,比如__prepare__,类声明时创建命名空间
- 加载顺序
- 类名空间声明 —> 类静态方法(类的工具函数)—> 类方法(类的构建) —> 类对象创建完成 —>实例
- 示例
- 类方法
__prepare__
类装配,为类声明创建命名空间,返回一个字典 - 类的静态方法
__new__
类函数
_ 类的实例方法__init__
实例使用,方法定义
- 类方法
类的特殊成员(属性和方法)
- 背景
- python没有显性的接口,用的是一种“约定”的协议机制
- 以特殊名字的方法、属性未提供特殊的功能
- 常用特殊方法
__repr__()
对象的自我描述 通常用来告诉外界该对象具有的状态信息- object类已实现该方法, 即返回 “类名+object at+内存地址”值
__del__()
与__init__()
相对应, 它是用于销毁python对象- 只有对象的引用计数变成 0 时,该对象变量执行 del 操作才会被回收
__dir__
方法用于列出该对象内部的所有属性(包括方法)名的序列- 对某个对象执行 dir(object) 函数时,实际上就是将该对象的 dir() 方法返回值进行排序,然后包装成列表
__dict__
属性 用于查看对象内部存储的所有属性名和属性值组成的字典__call__
实例对象是否可调用
- 动态检查对象属性
hasattr(obj, name)
检查 obj 对象是否包含名为 name 的属性或方法getattr(object, name[, default])
获取 object 对象中名为 name 的属性的属性值setattr(obj, name, value,/)
将obj 对象的 name 属性设为 value
- 序列相关特殊方法
__len__
返回值决定序列中元素的个数__getitem__
该方法指定索引对应元素, key 应该是整数值或 slice 对象__contains__
判断序列中是否包含指定的元素__setitem__
设置指定索引的元素__delitem__
删除指定索引对应的元素
- 实现迭代器
__iter__
返回一个迭代器(iterator), 迭代器必须包含一个__next__()
方法,该方法返回迭代器的下一个元素__reversed__(self)
为内建的reversed()反转函数提供支持- 可使用内置的 iter() 函数将列表、元组等转换成迭代器
- 生成器
- 生成器 VS 迭代器
- 迭代器通常是先定义一个迭代器类,然后通过创建实例来创建迭代器
- 生成器则是先定义一个包含 yield 语句的函数,然后通过调用该函数来创建生成器
- 二者调用后都返回一个实例,后者只不过是生成器对象
yield
语句特点- 每次返回一个值,有点类似于 return 语句
- 冻结执行,程序每次执行到 yield 语句时就会被暂停
- 冻结之后,当程序再次调用 next() 函数获取生成器的下一个值时,程序才会继续向下执行
- 生成器创建方式
- 使用 for 循环的生成器推导式
- 调用带 yield 语句的生成器函数
- 生成器方法
- 让生成器与“外部程序”动态地交换数据, 生成器的
send()
方法 - 当生成器运行起来之后, 外部程序通过 send() 方法发送数据, 生成器函数使用 yield 语句接收收据
- 生成器close():该方法用于停止生成器
- throw():该方法用于在生成器内部(yield 语句内)引发一个异常
- 流程 send(None) --启动 – yield后返回 – yield语句接收 — 下一yield返回
- next外部取值 ,send外部发值 , yield内部“冻结”
- 让生成器与“外部程序”动态地交换数据, 生成器的
- 生成器 VS 迭代器
异常处理
- try 块放置可能引发异常的代码
- 在 except 后对应的是异常类型和一个代码块,用于表明该 except 块处理这种类型的代码块
- 在多个 except 块之后可以放一个 else 块,表明程序不出现异常时还要执行 else 块
- 最后还可以跟一个 finally 块,finally 块用于回收在 try 块里打开的物理资源,异常机制会保证 finally 块总被执行
- raise 用于引发一个实际的异常,raise 可以单独作为语句使用,引发一个具体的异常对象
python类和对象
- 概述
- 类通常是某一批对象的抽象,对象是某个具体存在的实体
- 类变量用于定义属于类本身所包含的状态数据,实例变量定义对象所包含的状态数据
- 方法则用于定义该类的对象的行为或功能的实现
- python动态性
- 实例变量可以动态的增加或删除, 可通过del语句删除已有对象的实例变量
- 类中定义的方法默认是实例方法,实例方法的第一个参数会被绑定到方法的调用者(该类实例 self)
- 类对象的创建和使用
- 方法的第一个形参self是自动绑定, 它会被绑定到方法的调用者
del p.name
删除p对象的name实例变量
- 动态添加变量和方法
- 注意!!!
- 【为实例对象动态增加的方法,Python不会自动将调用者自动绑定到第一个参数】
- 解决方案 因此程序必须手动为第一个参数传入参数值,用以绑定实例
- 动态增加的方法,需要指定调用者
- 注意!!!
types.MethodType
为动态增加方法,自动绑定到参数动态方法
self 调用者
- 第一参数绑定策略
- 在构造方法中引用该构造方法正在初始化的对象
- 在普通实例方法中引用调用该方法的对象
- 关键
- 方法的第一个参数所代表的对象类型是确定的,只能是当前类的实例
- 仅当这个方法被调用时,它所代表的对象才被确定下来谁在调用这个方法,方法的第一个参数就代表谁
- 当心
- Python 对象的一个方法调用另一个方法时,不可以省略 self
- Python 的类、对象有点类似于一个命名空间,如果直接调用某个方法,这种形式属于调用函数
- Python的类在很大程序上是一个命名空间
- 未绑定方法
- python类可以调用实例方法
- 但使用类调用实例方法时, python不会自动为方法的第一个参数self绑定参数值
- 程序必须显式地为第一个参数self传入方法的调用者,此谓未绑定方法
- 类方法 VS 静态方法
- python类方法的第一个参数(通常建议参数名为 cls)会自动绑定到类本身,@classmethod 修饰的方法
- 对于类的静态方法则不会自动绑定, 使用
@staticmethod
修饰的方法 - 应用场景
- 一般不需要使用类方法或静态方法,程序完全可以使用函数来代替类方法或静态方法
- 在特殊的场景(比如使用工厂模式)下,类方法或静态方法就必不可少了
- 函数装饰器
- 使用@符号引用已有的函数后, 可用于修饰其他函数,装饰被修饰的函数
- 被修饰的函数总是被替换成 @ 符号所引用的函数的返回值
- 应用场景
- 比如权限检查,记录日志
- 原理 不需要修改被装饰函数的代码,只要增加一个修饰
- 扩展 在其它编程语言中称之为AOP,面向切面编程
- python 类命名空间
- Python 的类就像命名空间
- Python 同样允许在类范围内放置可执行代码,当 Python 执行该类定义肘,这些代码同样会获得执行的机会
- 对于在类命名空间内定义的 lambda 表达式,则相当于在该类命名空间中定义了一个函数,这个函数就变成了实例方法
- 类变量 VS 实例变量
- python允许使用对象来访问该对象所属类的类变量(推荐使用类访问类变量)
- 程序通过对象访问类变量,其本质还是通过类名在访问类变量
- 如果程序通过对象对类变量赋值,其实不是对“类变量赋值”,而是定义新的实例变量
- property函数
- 使用(本质上是对属性权限的访问控制)
- 若为 Python 类定义了 getter、setter 等访问器方法,则可使用 property() 函数将它们定义成属性(相当于实例变量)
x = property(fget=None, fset=None, fdel=None, doc=None)
- 分别代表 getter 方法、setter 方法、del 方法和 doc,对应权限只读,只写,可删除,含文档
- 计算属性 类似于property合成属性
- @property 装饰器修饰的方法,使之称为属性,默认值只读
- @property x
- @x.setter
- @x.deleter
- 使用(本质上是对属性权限的访问控制)
python 面向对象
- 封装
- 意义 隐藏细节 暴露接口方法
- python并不支持真正隐藏,不提供private关键字, 通过
__
开头,以示隐藏,程序无法直接访问 - 在这些方法名前添加单下画线和类名再加原双下划线方法,可达到访问‘隐藏方法’
- 小结
- Python 并没有提供真正的隐藏机制,所以 Python 类定义的所有成员默认都是公开,只是提供了一些小技巧
- 继承
- Python 的继承是多继承机制
- 排在前面的父类中的方法会“遮蔽”排在后面的父类中的同名方法
- 父类方法重写
- 子类包含与父类同名的方法的现象被称为方法重写(Override),也被称为方法覆盖
- 使用未绑定方法调用被重写的方法
- 在通过类名调用实例方法时,Python 不会为实例方法的第一个参数 self 自动绑定参数值,而是需要程序显式绑定第一个参数 self
- 调用父类的构造方法
- 使用未绑定方法,因为构造方法也是实例方法,当然可以通过这种方式来调用
- 使用 super() 类调用父类的构造方法
- _
_slots__
- 限制类实例动态添加属性和方法
__slots__
属性的值是一个元组,该元组的所有元素列出了该类的实例允许动态添加的所有属性名和方法名- 对于 Python 而言,方法相当于属性值为函数的属性
- slots 属性指定的限制只对当前类的实例起作用,对该类派生出来的子类是不起作用
type
函数 动态创建类class
定义的所有类都是type
类的实例, type类的实例就是类类型- Python 完全允许使用
type()
函数(相当于type
类的构造器函数)来创建type
对象 - 动态建类流程
type(object_or_name, bases, dict)
type(object)
返回object
的type
type(name, bases, dict)
返回一个新的type
metaclass
元类(创建类的类)- 使用
metaclass
可以在创建类时动态修改类定义 metaclass
应继承type
类, 并重写 new() 方法
- 使用
metaclass
类的 new 方法- 当程序使用
class
定义新类时,如果指定了metaclass
,metaclass
的 new 方法就会被自动执行
- 当程序使用
- 应用场景
- 通过使用
metaclass
可以动态修改程序中的一批类,对它们集中进行某种修改 - 在开发一些基础性框架时非常有用,程序可以通过使用
metaclass
为某一批需要具有通用功能的类添加方法 - 弥补缺接口与实现的功能
- 通过使用
- 多态
- 当同一个变量在调用同一个方法时,完全可能呈现出多种行为(具体呈现出哪种行为由该变量所引用的对象来决定)
- 检查类型
issubclass(cls, class_or_tuple)
检查cls
是否为后一个类或元组包含的多个类中任意类的子类isinstance(obj, class_or_tuple)
检查 obj 是否为后一个类或元组包含的多个类中任意类的对象- 原则 先检查,再调用方法
- enum.Enum 枚举类
- 类的对象是有限且固定
- 定义
- 直接使用 Enum 列出多个枚举值来创建枚举类
- 通过继承 Enum 基类来派生枚举类