Pyhton中有大量双下划线__开头结尾的魔法方法,有点类似C++的运算符重载。
一、构造和初始化
__init__:用于构造对象。
调用obj = SomeClass()时,首先调用__new__方法构建实例,然后调用__init__传递参数。
二、访问器方法
Python能够定义私有属性,然后提供公共可访问的getter和setter,通过魔术方法来实现封装。
__getattr__(self, name)
该方法定义了访问一个不存在的属性时的行为。
因此,重载该方法可以实现捕获错误拼写然后进行重定向,或者对一些废弃的属性进行警告。
#######################################
__setattr__(self, name, value)
对属性进行赋值和修改操作时的行为。
不管对象的某个属性是否存在,它都允许为该属性进行赋值,因此可以为属性的值进行自定义操作。
PS:实现__setattr__时要避免无限递归
#######################################
# 每一次属性赋值时, __setattr__都会被调用,因此不断调用自身导致无限递归
def __setattr__(self, name, value):
self.name = value
# 正确写法
def __setattr__(self, name, value):
self.__dict__[name] = value
三、定制类的能力
比如Java中的string类型、包括所有包装类,比较两个对象内容是否相等,不能使用==,而需要调用equals方法,Python通过魔法方法可以拓展定制类的能力,例如进行自定义对象的比较。
__cmp__(self, other),__cmp__是最基本的用于比较的魔术方法。
self < other:返回负数
self == other:返回0
self > other:返回正数
__eq__(self, other) 定义等号的行为,==
__ne__(self, other) 定义不等号的行为,!=
__lt__(self, other) 定义小于号的行为,<
__gt__(self, other) 定义大于等于号的行为,>=
四、魔法方法不完全列表
| 魔术方法 | 调用方式 | 解释 |
|:--------------------------------|:----------------------------------|:------|
|**__new__(cls [,...])** |instance = MyClass(arg1, arg2) |创建实例
|**__init__(self [,...])** |instance = MyClass(arg1, arg2) |创建实例
|**__cmp__(self, other)** |self == other, self > other, .... |比较
|__pos__(self) |+self |一元加运算符
|__neg__(self) |-self |一元减运算符
|__invert__(self) |~self |取反运算符
|__index__(self) |x[self] |对象被作为索引使用
|**__nonzero__(self)** |bool(self) |对象的布尔值
|__getattr__(self, name) |self.name # name不存在 |访问一个不存在的属性
|__setattr__(self, name, val) |self.name = val |对一个属性赋值
|__delattr__(self, name) |del self.name |删除一个属性
|__getattribute(self, name) |self.name |访问任何属性
|__len__(self) |len(self) |返回当前对象长度
|**__getitem__(self, key)** |self[key] |使用索引访问元素
|**__setitem__(self, key, val)** |self[key] = val |对某个索引值赋值
|__delitem__(self, key) |del self[key] |删除某个索引值
|**__iter__(self)** |for x in self |迭代
|**__contains__(self, value)** |value in self, value not in self |使用in操作测试关系时
|**__concat__(self, value)** |self + other |连接两个对象时
|__call__(self [,...]) |self(args) |调用对象
|**__enter__(self)** |with self as x: |with声明上下文管理
|__exit__(self, exc, val, trace) |with self as x: |with声明上下文管理
|__getstate__(self) |pickle.dump(pkl_file, self) |序列化
|__setstate__(self) |data = pickle.load(pkl_file) |序列化
五、Python3变化
__cmp__被取消,因为和其他魔法方法有功能上的重复。
__nonzero__被重命名成__bool__。
参考: