类和对象创建
__new__
, 根据类创建对象,控制创建对象的过程,例如创建单例类。接收类对象,及构建对象的参数;返回创建的对象
__init__
,对象属性的初始化。接收new魔法方法创建的对象,及构造对象的参数(与new魔法方法的对象参数一致),返回None
__del__
,当对象被释放的时候要干什么事情,但是del关键字只会减少对象的引用,在对象的引用数量为0且触发了gc.colloction时才会释放对象并触发del方法
__init_subclass__
初始化子类。在衍生类继承基类的时候触发。class Base: def __init_subclass__(cls, name, *args): """ 初始化子类,可以接受子类继承过程中传递的参数 """ cls.name = name cls.x = {} class A(Base, name=1): """ 继承的同时,可以传递位置参数 """ pass A.x print(A.name) # print 1
__class_getitem__
可以对类取方括号subscribeclass A: def __class_getitem__(cls, item): print(item) return "value" print(A['a']) # print value
type hint就是通过该魔法方法实现的
__mro_entries__
帮助继承的子类找到父类。有这个特殊方法的原因具体看PEP560class A: def __mro_entries__(self, bases): """ 返回基类组成的元组 """ print(base) return (A, ) class B(A()): pass
__prepare__
返回被继承类的属性或方法字典class Meta(Type): @classmethod def __prepare__(self, name, bases, **kwargs): return {"name": "xiaoming"} class A(metaclass=Meta): pass print(A.name) # print xiaoming
__instancecheck__
校验是否是同一个类或子类关系
__subclasscheck__
校验是否是子类关系class Meta(type): def __instancecheck__(self, instance): return True def __subclasscheck__(self, subclass): if subclass is int: return True else: return False class A(metaclass=Meta): pass o = A() print(isinstance(123, A)) # True print(issubclass(int, A)) # True
对象打印
__repr__
打印对象的时候调用并返回该方法结果
__str__
比repr更注重可读性,repr方法同时定义时优先触发str方法
__format__
常用实例:print(f"15:b")打印15的2进制,print(f"15:x")打印15的16进制,def __format__(self, spec): """ 判断输入的format spec是否是x,输出不同结果 """ if spec == 'x': return '十进制' else: return '<n>'
__bytes__
如果对象由bytes(obj)调用的时候,触发该方法。或者类似bytes方法调用时候触发
比较运算
__eq__
两个对象用==号触发,如果没有定义eq方法,会使用 is 来代替。如果定义了ne方法也可以用该方法触发,会将结果取反。
__ne__
两个对象使用 !=号触发,如果定义了eq方法也可以用该方法触发,会将结果取反。
__gt__
两个对象使用 > 或 < 号触发。但调用哪个对象的该方法不确定。
__lt__
两个对象使用 > 或 < 号触发。但调用哪个对象的该方法不确定。一般调用左边类的魔法方法,但是如果右边的类是左边类的子类的时候会调用右边类(子类)的魔法方法。
__le__
小于等于,解释器不会对该运算符做推理(不会用小于或者等于来代替)
__hash__
返回整数,两个相等的对象必须返回同一个hash值,官方建议在hash函数中返回当前对象核心属性的tuple的hash结果
__bool__
求bool场景下返回对象的布尔结果,例如 if obj 场景;
算数运算
__add__
让类支持 + 操作
__radd__
定义反过来运算的逻辑;所有运算符都有该魔法方法;
__iadd__
v1 += v2 ;inplace版本;返回self本身;所有运算符都有该魔法方法
__sub__
让类支持 - 操作
__mul__
让类支持 * 操作
__matmul__
让类支持 @ 操作 矩阵乘法
__truediv__
让类支持 / 操作
__floordiv__
让类支持 // 操作
__mod__
让类支持 % 操作,求余
__divmod__
让类支持 divmod 操作,即拿到商又拿到余数
__pow__
让类支持 ** 和pow操作。其中pow支持同时的mod操作,pow(a, b, mod=mod) ⇒ a ** b % mod
有时该操作会更加快速
__lshift__
v1 << v2 位运算
__rshift__
v1 >> v2 位运算
__invert__
~v1;一般用作位运算
__and__
v1 & v2;并不是重写了 and关键字
__or__
v1 | v2;并不是重写了 or 关键字
__xor__
v1 ^ v2
__pos__
+v1;返回新的值;在前面有正号时调用
__neg__
-v1;返回新值;在前面有负号时调用
__abs__
abs(v1) 时调用
__complex__
complex(v1) 返回类型必须为complex
__int__
int(v1)时调用 返回类型必须为int
__float__
float(v1)时调用 返回类型必须为float
__index__
当把当前对象当成一个索引使用的时候希望得到的返回值;定义了index之后,int(v1),float(v1),complex(v1)都可以使用。class Index: def __index__(self): return 1 index = Index() lst = [1, 2, 3, 4, 5] print(lst[index]) # print 2
__round__
原函数逻辑四舍六入五看奇偶。通过该方法改变原方法的意思
__trunc__
返回整数部分,忽略小数部分
__floor__
向下取整,在操作负数的时候与trunc函数返回不同
__ceil__
向上取整。操作正数时与trunc函数不同print(math.trunc(-1.1)) # print -1.0 print(math.floor(-1.1)) # print -2.0 print(math.ceil(1.1)) # print 2.0
操作的两个对象不一定是同一个类型,只有在调用前一个对象的对应魔法方法时不失败即可。或在r方法中尝试调用成功也可以。
对象属性
__getattr__
获取一个不存在的属性会调用该方法。接收属性名称,返回属性结果。当获取存在的属性时,不会调用该方法。常常在该方法中获取对象的其他存在的属性,且该调用方式获取的是存在的属性因此不会递归调用该方法,因此就不存在递归调用。
__getattribute__
获取属性不论是否存在都会调用该方法。接收属性名称,返回结果。在想要返回默认值的时候一定要使用super().__getattribute__(name)
如果使用getattr(self, name)会出现无限递归。因为getattr函数又会调用getattribute方法就这样一直递归下去。该方法很容易出现无限递归,例如def __getattribute__(self, name): # 在获取counter属性的时候又调用了当前方法,此时出现自调用的无限递归 self.counter += 1 return super().__getattribute__(name)
__setattr__
为对象的某个属性设置一个值,方法中常使用super().__setattr___(name, val)
来进行默认的操作。
__delattr__
删除对象的属性时会调用。del obj.data 。同样使用super().__delattr__(name)
来调用默认方式
__dir__
获取当前属性的所有属性或方法
模拟
__call__
将对象转换为callable;
__len__
返回容器的长度;len(v1) ;如果该容器类没有定义bool方法,那么解释器尝试调用len方法,如果len返回长度为0,那么为False,如果长度不为0,那么为True;
__getitem__
使用方括号读取值时调用该方法;支持切片操作
__setitem__
使用方括号设置值的时候调用该方法;
__delitem__
删除一个item时调用
__reversed__
使用reversed(v1),调用该方法,默认对数据进行反转
__containes__
使用in操作时候调用返回True或False。例如,2 in [2, 3, 4]
__iter__
返回容器的iterator。使该对象成为可迭代对象;使对象支持for循环等
__missing__
继承dict时,在获取不到dict中某个键时,调用该方法,获取返回值
__enter__
__exist__
上下文管理器context;即使上下文报错,仍然可以成功调用exist方法;enter方法常返回上下文管理器本身self;
描述符
class D: """ 定义一个描述符 """ def __init__(self): self.val = 0 def __set_name__(self, owner, name): """" 在类定义中实例化当前类,就会触发该魔法方法;可以不是描述符 :owner: 实例化该类所在的类 :name: 当前对象所在类的属性名 """" print(owner, name) def __get__(self, obj, owner=None): """ 在获取对象的描述符的时候会调用 :self: 当前描述符对象 :obj: 调用该描述符的对象,当前例子中为o, :owner: 调用该描述符的类,当前例子中为A """ return self.val def __set__(self, obj, value): """ 在为描述符赋值的时候触发 :self: 当前描述符对象 :obj: 调用该描述符的对象,当前例子中为o :value: 要赋予的新值 """ self.val = value def __delete__(self, obj): """ 删除描述符时调用 """ print("delete") class A: d = D() o = A() o1 = A() # 在获取对象的描述符的时候会调用该描述符的get魔法方法,且描述符是类属性级别的,所有对象共享该类的描述符 print(o.d) # print 0 o.d = 2 print(o.d) # print 2 print(o1.d) # print 2 del o.d # print delete