魔术方法
python精华之一
特殊属性
__name__ 类,函数,方法等的名字
__modle__ 主模块,当前的模块__main__,其他模块调用返回模块对象
__class__ 相当于type,对象或类所属的类
__bases__ 返回基类的元组,顺序为基类列表中出现的顺序
__doc__ 文档,未定义为None
__mro__ 类的mro,定义时就会计算并放在类的属性里的__mro__中
__dict__ 类或实例的属性,可写的字典,这里注意有些只读字典
查看属性
__dir__ 返回类的或者对象的所有成员的列表,
dir()函数调用__dir__(),dir是内建函数,
如果类中和实例中定义了__dir__:
使用实例调用时,实例中如果定义了__dir__,就会覆盖类__dir__,返回实例中的__dir__的运行结果;
如果实例中没有,就会调用父类的,如果父类没有,就继续向上找,中间有的话就会运行该方法;
如果类中和实例中没有定义__dir__:
如果对象是模块对象,返回的列表包含文件的属性名和变量名,受作用域影响,一般在模块上使用时,调用模块,在自己的模块搜集
如果对象是类或类的实例,近似于自己实例的字典加类的字典加object的字典,返回列表包含类的属性名,及它的基类的属性名
如果dir() 括号中不写,返回的列表包含不同的内容
在模块中,返回模块的属性和变量名
在函数中,返回本地作用域的变量名
在函数中,返回本地作用域的变量名
魔术方法
创建,初始化与销毁
__new__ 实例化,可以不写,会去调父类的方法。一定要return,返回不要再调自己,调本类型的实例,如果不是cls的实例,就不会调用__init__,即使创建了该方法,也会使用return super().__new__(cls), 最后调用的是object的__new__方法创建并返回实例
__init__
__del__
__hash__ 内建函数hash()调用后的返回值,返回整数,现在Linux的加密主要使用的MD5算法也是hash算法的一种,
哈希算法,具有幂等性,同一个程序中不论计算多少次,相同的对象返回的hash的值都一样,
不同的hash算法,可能会产生hash冲突,不同的x可能求得同样的值
__eq__ 判断是否相同,返回一个bool值,hash函数只负责计算hash,去重需要__eq__判断,
一般hash只要不冲突,就不会调用__eq__,__eq__ 对应 '==' 操作符,判断两个对象是否相等,返回bool。
一旦类中提供__eq__ ,类中就会自动添加__hash__=None
hash值相等不代表对象相等,
list类的实例不可hash,在list类中,源码中有__hash__ = None,也就是说如果调用__hash__相当于调用None,
如果你创建的类不能被hash,那就把__hash__设置为None
import math class Point: def __init__(self, x, y): self.x = x self.y = y def __hash__(self): return hash((self.x, self.y)) def __eq__(self, obj): return self.x == obj.x and self.y == obj.y p1 = Point(3, 0) p2 = Point(0, 4) p3 = Point(3, 0) print({p1, p2, p3})##可以去重
__bool__ 内建函数bool(),或者对象放在逻辑表达式的位置,调用这个函数返回布尔值
没有定义__bool__()的,就去__len__()返回长度,非零为真
可视化方法
__repr__ 内建函数repr()对一个对象获取字符串表达,
调用__repr__方法返回字符串,间接调用会调,如果未定义,直接返回object的定义,也就是显示内存地址的信息
__str__ 实例直接print(),或者str(),或者format(),调用时,要返回对象的字符串表达,
如果没有定义,就去调用__repr__方法返回字符串表达式,如果没有__repr__定义,就直接返回对象的内存地址
类不提供__str__,就使用__repr__;不提供__repr__就去object找,
要注意:打印对象,输出形式,打印出来的类型不作数,并不能真正的表达对象的类型!
__bytes__ 提供bytes方法,bytes()函数调用,返回一个对象的bytes表达,即返回bytes对象
运算符重载
< __lt__ 小于 lessthan
<= __le__ 小于等于 lessequal
> __gt__ 大于 greatthan
>= __ge__ 大于等于 greatequal
== __eq__ 等于 equal ,只有==才调用
!= __ne__ 不等于 notequal
+ - * / __add__ ,__sub__ ,__mul__ ,__truediv__ 加减乘除重载
% __mod__ 取模运算重载
// __floordiv__ 整除重载
** __pow__ 乘方重载
divmod __divmod__ 取模取余
+= ,-= , *= , /= , %= , //= , **= __iadd__ , __isub__ , __imul__ , itruediv__ , __imod__ , __ifloordiv__ , __ipow__ ,其中的 i 表示in place,立即返回
如果不定义加等,就去调add,在赋值给左边的值,其他的运算也是
实例之间的计算,可以用坐标点来理解
import math
class Point: def __init__(self,x,y): self.x = x self.y = y def __eq__(self,obj): return self.x ==obj.x and self.y == obj.y def __add__(self,other): return Point(self.x + other.x,self.y+other.y) def __sub__(self,other): return Point(self.x - other.x,self.y-other.y) def __repr__(self): return "({},{})".format(self.x,self.y)
还可以使用total ordering 模块,但是要提供等于和大小与四种之中的一种,一般自己写,写三个,等于,大小于中的一个,和大于小于中的一个,就可以推断另一个
大于推断小于
等于推断不等于
大于等于推断小于等于
用total ordering 可能产生性能问题,尽量自己写,
类的大量运算,运算符是较常见的表达方式,提供运算符重载比提供加法方式更符合使用者的习惯
可参见int的所有的操作符,几乎实现了所有的操作符
容器相关方法
__len__ 内建函数len(),返回对象的长度(>=0),将对象看作容器,bool()函数调用时,没有__bool__属性时,就会来判断__len__是否存在,如果存在且不为0,就返回真
__iter__ 迭代容器内容时,返回一个迭代器对象
__contains__ in成员运算符,没有实现,就调__iter__遍历,查找都要遍历,可以不写contains
__getitem__ 实现self [ key ] 访问,如果是序列对象,key就是整数索引,或者是切片,对于字典和集合,key是hashable的,不存在就KeyError
__setitem__ 和getitem访问类似,是设置值的方法
__missing__ 字典和类使用时,__getitem__()调用key不存在时执行