魔术方法
查看类的魔术方法
输出结果如下
在Python中,所有以__
双下划线包起来的方法,都统称为魔术方法。比如最常见的 __init__
。
创建/销毁
__new__
: object.__new__(cls)
创建类的方法:构造函数__del__
:删除类:析构函数__init__
:初始化函数
每当实例空间被收回时(在垃圾收集时),__del__
就会自动执行。
运算符重载
类的对象之间可以进行加减运算,只要类实现了加减运算对应的魔术方法即可。加法的具体实现是__add__
,减法的具体实现是__sub__
。
- 具体运算符对应的重载函数可以参考int类中运算符重载的实现:help(int)
不要过度使用运算符重载
__add__
的具体实现如果写成了减法,这种类型的错误非常不容易发现,因此如果不是在写库给第三方使用的时候,基本用不上运算符重载。
hash
- 使用内置函数
hash
对某个对象求hash值时, 会调用对象的__hash__
方法,示例代码如下
__hash__
方法必须返回int,否则会抛出TypeError
- 可hash对象,就是具有
__hash__
方法的对象
- 一个类如果没有重写
__hash__
方法的话,这个类的每个对象,通常具有不同的hash
- 通常
__hash__
会和 __eq__
一起使用, 因为解释器通常同时判断hash是否相等以及实例是否相等
大小
当对象实现了__len__
方法时,可以使用内置方法len
求对象的长度, __len__
方法必须返回非负整数
因此内置函数和__len__
方法的效果相同。
bool
- 当对象o实现了
__bool__
方法时, bool(o)
返回值为o.__bool__()
- 当对象o没有实现
__bool__
方法时,如果o实现了__len__
方法, bool(o)
返回值为 len(o) != 0
- 当对象o既没有实现
__bool__
方法,也没有实现 __len__
方法的时候, bool(o)
返回值为True
可视化
__str__
方法,print函数本质是调用对象的__str__
方法,用于给人读__repr__
方法,repr函数本质是调用对象的__repr__
方法,用于给机器读
repr:返回对象的规范化的字符串表示
可调用对象
一个对象,只要实现了__call__
方法, 就可以通过小括号来来调用, 这一类对象,称之为可调用对象
给对象加上函数也就是对__call__
方法加上参数:
可调用对象的应用实例:实现可过期可换出的cache装饰器
用__call__
来实现可调用对象,和闭包是殊途同归的,通常是为了封装一些内部状态
上下文管理
支持上下文管理的对象
当一个对象同时实现了__enter__
和__exit__
方法,那么这个对象就是支持上下文管理的对象。
支持上下文管理的对象可以使用以下语句块进行处理:
比如
所以,with
开启一个语句块, 执行这个语句块之前,会执行 __enter__
方法, 执行这个语句块之后,会执行__exit__
方法,也就是说在这个语句块的前后会执行一些操作,因此也叫上下文。
- 即使with块抛出异常,
__enter__
和__exit__
也会被执行,所以上下文管理是安全的。
- 即使
with
块中主动退出解释器, __enter__
和__exit__
也能保证执行
with块的as字句
__enter__
方法
args和kwargs都是空的,因此上下文管理的时候__enter__
函数除self外,不带任何参数。
__exit__
方法
__exit__
的返回值,没有办法获取到,如果with
块中抛出异常 __exit__
返回False的时候,会向上抛出异常,返回True, 会屏蔽异常
__exit__
的三个参数 异常类型, 异常, traceback
args输出三个None,表示三个位置参数,kwargs为空,表示没有关键字参数。
- 使用变量接受
__exit__
的三个参数:exc_type,exc_value,traceback
上下文管理的应用场景
with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。即凡是在代码块前后插入代码的场景统统适用
- 资源管理
- 权限验证
以下以计时器为例
总共实现了两种计时方式,既可以对语句块计时,也可以对函数计时。
contextmanager的使用
contextlib是个比with优美的东西,也是提供上下文管理机制的模块,它是通过Generator装饰器实现的,不再是采用__enter__
和__exit__
。contextlib中的contextmanager作为装饰器来提供一种针对函数级别的上下文管理机制。
yield后面必须配合finally使用,否则如果抛出异常,程序不会执行yield后面的部门,也就是不会执行__exit__
部分。
反射
python的反射,核心本质其实就是利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,就是一种基于字符串的事件驱动!
关于模块的python反射以及反射机制分析参见:python反射机制深入分析
以下主要分析类对象的反射机制
getattr setattr hasattr
三个函数的原型:
- getattr:getattr(object, name[, default]) -> value。getattr(x, ‘y’)等效于x.y
- setattr:setattr(obj, name, value, /)。setattr(x, ‘y’, v)等效于x.y = v
- hasattr:hasattr(obj, name, /)
主要作用是通过对象的成员名称获取对象的成员
setattr的对象是实例,如果要给实例动态增加方法,需要先把函数转化为方法,转化的方法如下:
使用getattr setattr hasattr 实现一个命令路由器:
__getattr__
__setattr__
__delattr__
- 当一个类定义了
__getattr__
方法时,如果访问不存在的成员,会调用__getattr__
方法
增加__getattr__
方法
- 当一个类实现了
__setattr__
时, 任何地方对这个类的对象增加属性,或者对现有属性赋值,都会调用__setattr__
- 当一个类实现了
__delattr__
方法时,删除其实例的属性,会调用此方法