特殊属性
属性 |
含义 |
__name__ |
类、函数、方法的名称 |
__module__ |
类定义所在的模块名 |
__class__ |
对象或类所属的类 |
__bases__ |
类的基类的元组,顺序为它们在基类列表中出现的顺序 |
__doc__ |
类、函数的文档字符串,若没定义则为None |
__mro__ |
类的mro,方法查找顺序 |
__dict__ |
类或实例的属性,可写的字典 |
查看属性
__dir__:返回类或者对象的所有成员名称列表,dir()即调用__dir__(),若提供__dir__(),则返回属性的列表,否则会尽量从__dict__中收集多的信息
若dir([obj])参数obj包含__dir__()方法,该方法被调用。若参数obj不包含__dir__()方法,则将会收集尽量多的参数信息
对不同类型具有不同行为
若对象为模块对象,返回的列表包含模块的属性名
若对象为类型或类对象,返回的列表包含类的属性名、基类的属性名
否则,返回列表包含对象的属性名、类的属性名、类的基类的属性名
魔术方法
分类
创建、初始化、销毁
__init__、__del__
hash
bool
可视化
运算符重载
容器和大小
可调用对象
上下文管理
反射
描述器
其他
hash
hash的特点
固定大小
雪崩效应
单向不可逆
__hash__:内建函数hash()调用的返回值,返回一个整数,若定义该方法则该类的实例就可hash
__eq__:对应==,判断两个对象是否相等,返回bool值
__hash__仅返回一个hash值作为set或dict的key,但去重需要__eq__来判断2个对象是否相等
hash值相等只是hash冲突,不能说明两个对象相等
不可hash对象isinstan(obj,collections.Hashable) = False
__hash__ = None:设置类不能被hash
bool
__bool__:内建函数bool(),或者对象放在逻辑表达式的位置,调用该函数返回bool值,没定义__bool__()就找__len__()返回长度,长度非0为真,若__len__()也没有定义,则所有实例均返回真
可视化
__repr__:内建函数repr()对一个对象获取字符串表达。调用__repr__方法返回字符串表达,若__repr__没有定义,就直接返回object的内存地址信息
__str__:str()函数、内建函数format()、print()调用,需要返回对象的字符串表达。若未定义则调用__repr__返回字符串表达,__repr__未定义返回object的内存地址信息
__bytes__:bytes()函数调用,返回一个对象的bytes表达
运算符重载
<,<=,==,>,>=,!= |
__lt__,__le__,__eq__,__gt__,__ge__,__ne__ |
+,-,*,/,%,//,**,divmod |
__add__,__sub__,__mul__,__trudiv__,__mod__,__floordiv__,__pow__,__divmod__ |
+=,-=,*=,/=,%=,//=,**= |
__iadd__,__isub__,__imul__,__itrudiv__,__imod__,__ifloordiv__,__ipow__ |
@functools.total_ordering装饰器
__lt__,__le__,__eq__,__gt__,__ge__是比较大小必须实现的方法,但是全写太麻烦,使用该装饰器可简化代码
要求__eq__必须实现,剩余其他方法实现其一即可
缺点:引入了不需要的方法,影响性能
自己实现只需保证__eq__,__lt__或__gt__,__le__或__ge__五选三实现即可
容器
__len__:内建函数len(),返回对象的长度,若将对象当做容器类看,bool()函数调用时,若没有__bool__()方法,则看__len__()是否存在,存在返回非0
__iter__:迭代容器时调用,返回一个新的迭代器对象
__contains__:in成员运算符,若未实现就调用__iter__方法遍历
__getitem__:实现self[key]访问。序列对象,key接受整数为索引或切片,对于set或dict,key为hashable,可以不存在KeyError异常
__setitem__:设置值
__missing__:字典或其子类使用__getitem__()调用时,key不存在执行该方法
可调用对象
__call__:类中定义一个该方法,实例就可像函数一样调用
上下文管理
当一个对象同时实现了__enter__()和__exit__()方法,它就属于上下文管理的对象
__enter__:进入与此对象相关的上下文,若存在该方法,with语法会将该方法的返回值绑定到as字句中指定的变量上
__exit__():退出与此对象相关的上下文
实例化对象时不会调用__enter__,进入with语句块调用__enter__方法 –》执行语句体 –》离开with语句块调用__exit__()方法
安全性
存在异常,enter和exit照样执行,上下文管理是安全的
方法的参数
__enter__方法没有参数
__exit__方法有3个参数,与异常相关,没有异常则3个参数均为None
exc_type,异常类型
exc_value,异常的值
traceback,异常的追踪信息
__exit__方法返回一个等效True的值,可以压制异常,否则继续抛出异常
应用场景
增强功能
在代码执行的前后增加代码,以增强其功能,类似装饰器
资源管理
打开文件需要关闭
权限验证
在执行代码前做权限的验证
contextlib.contextmanager
装饰器,实现上下文管理,装饰一个函数,而不用像类一样实现__enter__()和__exit__()方法
对下面的函数有要求,必须有yield,必须返回一个生成器,且只有一个yield值
该装饰器接收一个生成器对象作为参数
若业务逻辑简单可使用contextlib.contextmanager,若复杂,用类增加__enter__()和__exit__()方法更方便
反射
概述
运行时,区别于编译时,指的是程序被加载到内存中执行的时候
反射,reflection,指的是运行时获取类型定义信息
在Python中,能通过一个对象,找出其type、class、attribute或method的能力,称为反射或自省
具有反射能力的函数:type()、isinstance()、callable()、dir()、getattr()
相关函数及方法
通过属性字典__dict__可以访问对象的属性,本质上就是利用反射的能力
内建函数 |
意义 |
getattr(object, name[, default]) -> value |
通过name返回object的属性值,当属性不存在返回default,若无default则抛出AttributeError,name必须为字符串 |
setattr(obj, name, value) |
object的属性存在则覆盖,不存在则新增 |
hasattr(obj, name) |
判断对象是否有该属性,name必须为字符串 |
这种动态增删属性的方式是运行时改变类或实例的方式,但装饰器或Mixin在定义时就写定了,反射具有更大的灵活性
反射相关魔术方法
__getattr__():一个类的属性会按照继承关系查找属性,若找不到,就会执行__getattr__()方法,如果没有该方法,则抛出AttributeError
属性查找顺序:instance.__dict__ ——》 instance.__class__.__dict__ ——》继承的祖先类(直到object)的__dict__ ——》找不到 ——》调用__getattr__()
__setattr__():实例通过.点设置属性,如self.x = x就会调用__setattr__()。若属性要加到实例自己的__dict__中,就需要自己完成
__setattr__()方法可以拦截对实例属性的增加、修改操作,若要设置生效,就需要自己操作实例的__dict__
__delattr__():可以阻止通过实例删除属性的操作,但通过类依然可以删除属性
__getattribute__:实例的所有属性访问,都会第一个调用__getattribute__方法,它阻止了属性的查找,该方法应该返回一个值(计算后的)或抛出一个AttributeError异常
该方法的return值将作为属性查找的结果。如果抛出AttributeError,则会直接调用__getattr__方法,表示属性没有找到
__getattribute__方法中为了避免该方法出现无限递归,其实现应该永远调用基类的同名方法以访问需要的任何属性
魔术方法 |
意义 |
__getattr__() |
当通过搜索实例、实例的类及祖先类查不到属性时,就会调用该方法 |
__setattr__() |
通过.访问实例属性,进行增加、修改 |
__delattr__() |
当通过实例来删除属性时调用此方法 |
__getattribute__() |
实例的所有属性调用都从此方法开始 |
属性查找顺序:实例调用__getattribute__() ——》instance.__dict__——》instance.__class__.__dict__ ——》继承的祖先类(直到object)的__dict__ ——》调用__getattr__()
描述器
class A含有__get__、__set__、__delete__方法中的任意一个,class B的类属性x为class A的实例,对class B或B的实例的x属性的读取,成为对class A的实例的访问,就会调用class A中的方法,只有类属性是class A的实例才会调用class A中的方法
描述器的表现
3个魔术方法:__get__()、__set__()、__delete__()
方法签名
object.__get__(self,instance,owner)
object.__set__(self,instance,value)
object.__delete__(self,instance)
其中,self指代当前实例,调用者;instance是owner的实例;owner是属性所属的类
描述器定义
一个类实现了__get__、__set__、__delete__三个方法中的任何一个,就是描述器
若仅实现__get__,即为非数据描述器non-data descriptor
同时实现__get__、__set__就是数据描述器data descriptor
若一个类的类属性设置为描述器,则它被称为owner属主
属性的访问顺序
数据描述器 ——》实例的__dict__ ——》非数据描述器
本质:若类属性指代的是数据描述器,则实例中和类属性同名的属性将从__dict__中被删除,造成数据描述器优先访问的假象
原创文章,作者:ZBD20,如若转载,请注明出处:http://www.178linux.com/99067