Python中必须掌握的魔术方法!不知道你就太low了!
与__getattr__(self, name)不同,__setattr__ 是一个封装的解决方案。无论属性是否存在,它都允许你定义对对属性的赋值行为,以为这你可以对属性的值进行个性定制。实现__setattr__时要避免”无限递归”的错误。
__delattr__
与 __setattr__ 相同,但是功能是删除一个属性而不是设置他们。实现时也要防止无限递归现象发生。
__getattribute__(self, name)
__setitem__(self, key, value)
当你执行self[key] = value时,调用的是该方法。
__delitem__(self, key)
定义当一个项目被删除时的行为(比如 del self[key])。这只是可变容器协议中的一部分。当使用一个无效的键时应该抛出适当的异常。
__iter__(self)
返回一个容器迭代器,很多情况下会返回迭代器,尤其是当内置的iter()方法被调用的时候,以及当使用for x in container:方式循环的时候。迭代器是它们本身的对象,它们必须定义返回self的__iter__方法。
__reversed__(self)
实现当reversed()被调用时的行为。应该返回序列反转后的版本。仅当序列可以是有序的时候实现它,例如对于列表或者元组。
__contains__(self, item)
定义了调用in和not in来测试成员是否存在的时候所产生的行为。你可能会问为什么这个不是序列协议的一部分?因为当__contains__没有被定义的时候,如果没有定义,那么Python会迭代容器中的元素来一个一个比较,从而决定返回True或者False。
__missing__(self, key)
dict字典类型会有该方法,它定义了key如果在容器中找不到时触发的行为。比如d = {‘a’: 1}, 当你执行d[notexist]时,d.__missing__[‘notexist’]就会被调用。
一个例子
下面是书中的例子,用魔术方法来实现Haskell语言中的一个数据结构。
# -*- coding: utf-8 -*-classFunctionalList:''' 实现了内置类型list的功能,并丰富了一些其他方法: head, tail, init, last, drop, take'''def__init__(self, values=None):ifvalues isNone:self.values = []else:self.values = valuesdef__len__(self):returnlen(self.values)def__getitem__(self, key):returnself.values[key]def__setitem__(self, key, value):self.values[key] = valuedef__delitem__(self, key): delself.values[key]def__iter__(self):returniter(self.values)def__reversed__(self):returnFunctionalList(reversed(self.values))defappend(self, value):self.values.append(value)defhead(self):# 获取第一个元素returnself.values[0]deftail(self):# 获取第一个元素之后的所有元素returnself.values[1:]definit(self):# 获取最后一个元素之前的所有元素returnself.values[:-1]deflast(self):# 获取最后一个元素returnself.values[-1]defdrop(self, n):# 获取所有元素,除了前N个returnself.values[n:]deftake(self, n):# 获取前N个元素returnself.values[:n]
允许一个类的实例像函数一样被调用。实质上说,这意味着 x() 与 x.__call__() 是相同的。注意 __call__ 的参数可变。这意味着你可以定义 __call__ 为其他你想要的函数,无论有多少个参数。
__call__ 在那些类的实例经常改变状态的时候会非常有效。调用这个实例是一种改变这个对象状态的直接和优雅的做法。用一个实例来表达最好不过了:
定义了当一个代码块被执行或者终止后,会话管理器应该做什么。它可以被用来处理异常、执行清理工作或做一些代码块执行完毕之后的日常工作。如果代码块执行成功,exceptiontype,exceptionvalue,和traceback将会为None。否则,你可以选择处理这个异常或者是直接交给用户处理。如果你想处理这个异常的话,请确保__exit在所有语句结束之后返回True。如果你想让异常被会话管理器处理的话,那么就让其产生该异常。
# -*- coding: UTF-8 -*-classMeter(object):"""
对于单位"米"的描述器
"""def__init__(self, value=0.0):self.value = float(value)def__get__(self, instance, owner):returnself.valuedef__set__(self, instance, value):self.value = float(value)classFoot(object):"""
对于单位"英尺"的描述器
"""def__get__(self, instance, owner):returninstance.meter *3.2808def__set__(self, instance, value):instance.meter = float(value) /3.2808classDistance(object):"""
用米和英寸来表示两个描述器之间的距离
"""meter = Meter(10) foot = Foot()
使用时:
>>>d = Distance()>>>printd.foot>>>printd.meter32.80810.0
复制
有时候,尤其是当你在处理可变对象时,你可能想要复制一个对象,然后对其做出一些改变而不希望影响原来的对象。这就是Python的copy所发挥作用的地方。
__copy__(self)
定义了当对你的类的实例调用copy.copy()时所产生的行为。copy.copy()返回了你的对象的一个浅拷贝——这意味着,当实例本身是一个新实例时,它的所有数据都被引用了——例如,当一个对象本身被复制了,它的数据仍然是被引用的(因此,对于浅拷贝中数据的更改仍然可能导致数据在原始对象的中的改变)。
__deepcopy__(self, memodict={})
定义了当对你的类的实例调用copy.deepcopy()时所产生的行为。copy.deepcopy()返回了你的对象的一个深拷贝——对象和其数据都被拷贝了。memodict是对之前被拷贝的对象的一个缓存——这优化了拷贝过程并且阻止了对递归数据结构拷贝时的无限递归。当你想要进行对一个单独的属性进行深拷贝时,调用copy.deepcopy(),并以memodict为第一个参数。
附录
用于比较的魔术方法
数值计算的魔术方法
单目运算符和函数
双目运算符或函数
增量运算
类型转换
进群:125240963 即可获取源码!