Python中的魔法方法
Python中的魔法方法
一、什么是Python的魔法方法?
魔法方法就是Python的内置方法,不需要主动调用,存在的目的就是给Python的解释器进行调用,几乎每个
魔法方法都有一个对应的内置函数或者运算符,它们经常是使用两个下划线包围来命名的,最为常见的就是
__ init __方法了。总的来说魔法方法就是让我们对类添加魔法的特殊方法(说跟没有说一样)
二、常见的魔法方法
1.构造方法
最为常用的魔法方法就是__ init __方法了,我们可以使用它来指明一个对象初始化的行为。实际上,
当我们再实例化对象时,__ init __方法并不是第一个被调用的方法。事实上应该是new方法,当这个对
象的生命周期结束的时候,__ del __方法会被调用。下面具体阐述
(1)__ new __(cls,[....])
__ new __是对象实例化第一个调用的方法,它只取下cls参数并把其他的参数传递给init方法,它很少使用
(2)__ init __(self,[....])
这是类的初始化方法,它能获取任何传给构造器的参数,这个方法在类的定义中使用到的是最多的
(3)__ del __(self)
new和init都是对象的构造器,__ del __是对象的销毁器,它不是实现了语句del x,而是定义了对象被垃圾
回收时的行为。当对象需要销毁做一些处理的时候这个方法很有用,比如socket对象、文件对象。但是当
Python解释器退出但对象仍然存活的时候,__ del __并不会执行,所以要及时地手工清理对象
下面是一个示例:
from os.path import join
class FileObject:
#文件对象的装饰类,用来保证文件被删除时能够正确关闭
def __init__(self,filepath = '~',filename = 'sample.txt'):
self.file = open(join(filepath,filename),'r+')
def __del__(self):
self.file.close()
del self.file
2.运算符
(1)比较运算符
__ eq __(self,other) : 定义等于操作符的行为
__ ne __(self,other) : 定义不等于操作符的行为
__ lt __(self,other) : 定义小于操作符的行为
__ gt __(self,other) : 定义大于操作符的行为
__ le __(self,other) : 定义小于等于操作符的行为
__ ge __(self,other) : 定义大于等于操作符的行为
(2)一元操作符
__ pos __(self) : 实现取正的操作
__ neg __(self) : 实现取负的操作
__ abs __(self) : 实现内建绝对值函数abs()的操作
__ invert __(self) : 实现取反的操作
__ round __(self) : 实现内建函数round()的操作
__ floor __(self) : 实现math.floor()函数的操作
__ ceil __(self) : 实现math.ceil()函数的操作
__ trunc __(self) : 实现math.trunc()函数的操作,距离零最近的整数
(3)算数操作符
__ add __(self,other) : 实现加法的操作
__ sub __(self,other) : 实现减法的操作
__ mul __(self,other) : 实现乘法的操作
__ floordiv __(self,other) : 实现 // 操作符的整数除法
__ div __(self,other) : 实现使用 / 操作符的除法
__ mod __(self,other) : 实现取余函数的操作
__ pow __(self,other) : 实现pow()函数的操作
__ lshift __(self,other) : 实现左移位运算符
__ rshift __(self,other) : 实现右移运算符
__ and __(self,other) : 实现按位与运算符
__ or __(self,other) : 实现按位或运算符
__ xor __(self,other) : 实现按位异或运算符
(4)类型转换操作符
__ int__(self) : 实现到int的类型转换
__ float__(self) : 实现到float的类型转换
__ complex__(self) : 实现到complex的类型转换
__ oct__(self) : 实现到八进制数转换
__ hex__(self) : 实现到十六进制数转换
3.类的表示
使用字符串来表示类是一个相当有用的特性,在Python中有一些内建方法可以返回类的表示,也有
一系列魔性方法可以用来自定义在使用这些内建函数时类的行为
__ str __(self): 定义对类的实例调用str()的行为
__ repr__(self):与str()方法最大的区别就是str()的输出人类可读,repr()机器可读
__ unicode __(self):定义对类的实例调用unicode()的行为,返回unicode字符串
__ formate __(self): 定义当类的实例用于新式字符串格式化时的行为
__ hash __(self): 定义当类的实例调用hash()时的行为,它必须返回一个整数,结果用于字典中键的快速比较
__ nonzero __(self): 定义当类的实例调用bool()时的行为
__ dir __(self): 定义当类的实例调用dir()时的行为,这个方法会向调用者返回一个属性列表
4.访问控制
Python不是通过显式定义的字段和方法修改器,而是通过魔法方法实现了一系列的封装
- __ getattr __(self,name):当用户试图访问一个根本不存在的属性时,用户可以通过这个模型方法来定义类
的具体行为
- __ setattr __(self,name,value): 允许用户自己定义某个属性的赋值行为,不管这个属性是否存在
- __ delattr __ (self,name) :处理删除属性时的行为,使用时方式产生无限递归
5.自定义序列
有许多方法可以让自定义的Python类表现的像内建序列类型(字典、元组、列表、字符串等);当
想要创建自己的序列类型的时候,需要遵守某些协议。比如:不可变容器必须要定义__ len __方法和
__ getitem __方法;可变容器的协议除了上面提到的两个方法之外,还需要定义 setitem方法和delitem
方法;如果希望元素是可迭代的你需要定义__ iter __,这个方法返回一个迭代器。迭代器必须遵守迭
代器协议,需要定义__ iter __和next方法。容器背后的魔法方法如下:
- __ len __(self): 返回容器的长度,可变和不可变类型都需要实现
- __ getitem __(self,key):定义对容器中某一项使用self[key]的方式进行读取操作时的行为,可变和不可变
容器类型都需要实现这个方法。在没有键的类型时产生TypeError异常,没有和键值相匹配时会产生
KeyError异常
- __ setitem __(self,key):self[key]赋值操作时的行为,可变和不可变容器类型均需要实现,同时在合适的
时候产生KeyError和TypeError异常
- __ iter __(self,key):返回当前容器的迭代器。迭代器以一连串的内容返回,最常用的就是iter()函数调用,
以及在类似 for i in container:的循环中被调用。迭代器是他们自己的对象,需要定义__ iter __方法
__ contains__(self,item): 定义使用in 和 not in 进行成员测试时类的行为
__ reversed __(self): 定义了对容器使用 reversed()内建函数的行为,它应该返回一个反转之后的序列
__ missing __ (self,key): 定义了当视图访问一个字典中不存在的键时的行为
一个典型的示例:
class FunctionalList:
#这是一个列表的封装类,实现了一些额外的函数式:head、tail、init、last、drop和take
def __init__(self,values = None):
if values is None:
self.values = []
else:
self.values = values
def __len__(self):
return len(self,key)
def __getitem__(self,key):
#如果键的类型或值不合法,列表会返回异常
return self.values[key]
def __delitem__(self,key):
del self.values[key]
def __iter__(self):
return iter(self.values)
def __reversed__(self):
return reversed(self.values)
def append(self,value):
self.values.append(value)
def head(self):
return self.values[0]
def tail(self):
return self.values[1:] #取得除第一个元素外的所有元素
def init(self):
return self.values[:-1] #取得除最后一个元素外的所有元素
def last(self):
#取得最后一个元素
return self.values[-1]
def drop(self,n):
#取得除前n个元素外的所有元素
return self.values[n:]
def take(self,n):
return self.values[:n]
6.反射
__ instancecheck __ (self,check): 检查一个实例是否是你定义的类的一个实例
__ subclasscheck__(self,subclass):检查一个类是否是你定义类的子类
7.可调用对象
在Python中,函数也是一种对象,也就意味着它们可以像其他任何对象一样被传递到函数或者方法中,
- __ call __(self,[args....]): 允许一个类的实例像函数那样被调用,一般用于需要经常改变状态的类的实例
8.拷贝
当你想要改变一个对象而且不影响原有的对象时,可以使用Python中的copy模块
- __ copy __(self):定义对类的实例使用copy.copy()时的行为;copy.copy()返回一个对象的浅拷贝,即拷贝
出的实例是全新的,然而里面的数据全是引用的,浅拷贝中的数据更改会影响原对象
- __ deepcopy __(self,memodict=): 定义对类的实例使用deepcopy()时的行为。deepcopy()会返回一个
对象的深拷贝,这个对象和它的数据全都被拷贝了一遍。memodict是一个先前拷贝对象的缓存,它优化
了拷贝的过程,可以防止拷贝递归数据结构时产生无限递归;如果你想要拷贝一个单独的属性时,在那个
属性上调用copy.deepcopy()函数,使用memodict作为第一个参数
10.Pickling
Pickling是Python数据结构的序列化过程,当你想要存储一个对象再取出读取时,Pickling会显得十分有用
Pickle模块=不仅仅可以用于内建类型,任何遵守pickle协议的类都可以被pickle。Pickle协议有四个可选方法
- __ getnewargs__(self):通过这个方法改变类在反pickle时传递new函数的参数,返回一个参数元组
- __ getstate __ (self): 可以自定义对象被pickle的状态,而不是使用对象的dict属性;这个状态在反pickle时
会被__ setstate__使用
- __ setstate__ :和getstate方法相互依存;当这两个对象均被定义时,可以在pickle时使用任何方法保存对象
的任何状态
方法使用示例:
class Slate:
#存储一个字符串和一个变更日志的类 每次被pickle都会忘记当前值
def __init__(self,value):
self.value = value
self.last_change = time.asctime()
self.history = {}
def change(self,new_value):
#改变当前值。将上一个值记录到历史
self.history[self.last_change] = self.value
self.value = new_value
self.last_change = time.asctime()
def __getstate__(self):
#不返回self.value或者self.last_change
#反pickle时得到一个空白的slate
return self.history
def __setstate__(self):
self.history = state
self.value,self.last_change = None,None