Python 魔术方法

日常记录
原文地址:介绍Python的魔术方法 - Magic Method


init我们很熟悉了,它在对象初始化的时候调用,我们一般将它理解为"构造函数".

实际上, 当我们调用x = SomeClass()的时候调用,init并不是第一个执行的, new才是。所以准确来说,是newinit共同构成了"构造函数".

new是用来创建类并返回这个类的实例, 而init只是将传入的参数来初始化该实例.

new在创建一个实例的过程中必定会被调用,但init就不一定,比如通过pickle.load的方式反序列化一个实例时就不会调用init

new方法总是需要返回该类的一个实例,而init不能返回除了None的任何值。


getattr(self, name)
该方法定义了你试图访问一个不存在的属性时的行为。因此,重载该方法可以实现捕获错误拼写然后进行重定向, 或者对一些废弃的属性进行警告。

setattr(self, name, value)
setattr 是实现封装的解决方案,它定义了你对属性进行赋值和修改操作时的行为。
不管对象的某个属性是否存在,它都允许你为该属性进行赋值,因此你可以为属性的值进行自定义操作。有一点需要注意,实现setattr时要避免"无限递归"的错误,下面的代码示例中会提到。

delattr(self, name)
delattrsetattr很像,只是它定义的是你删除属性时的行为。实现delattr是同时要避免"无限递归"的错误。

getattribute(self, name)
getattribute定义了你的属性被访问时的行为,相比较,getattr只有该属性不存在时才会起作用。
因此,在支持getattribute的Python版本,调用getattr前必定会调用 getattributegetattribute同样要避免"无限递归"的错误。
需要提醒的是,最好不要尝试去实现getattribute,因为很少见到这种做法,而且很容易出bug。


get(self, instance, owner)
参数instance是拥有者类的实例。参数owner是拥有者类本身。get在其拥有者对其读值的时候调用。

set(self, instance, value)
set在其拥有者对其进行修改值的时候调用。

delete(self, instance)
delete在其拥有者对其进行删除的时候调用。


len(self)
需要返回数值类型,以表示容器的长度。该方法在可变容器和不可变容器中必须实现。

getitem(self, key)
当你执行self[key]的时候,调用的就是该方法。该方法在可变容器和不可变容器中也都必须实现。
调用的时候,如果key的类型错误,该方法应该抛出TypeError;
如果没法返回key对应的数值时,该方法应该抛出ValueError。

setitem(self, key, value)
当你执行self[key] = value时,调用的是该方法。

delitem(self, key)
当你执行del self[key]的时候,调用的是该方法。

iter(self)
该方法需要返回一个迭代器(iterator)。当你执行for x in container: 或者使用iter(container)时,该方法被调用。

reversed(self)
如果想要该数据结构被內建函数reversed()支持,就还需要实现该方法。

contains(self, item)
如果定义了该方法,那么在执行item in container 或者 item not in container时该方法就会被调用。
如果没有定义,那么Python会迭代容器中的元素来一个一个比较,从而决定返回True或者False。

missing(self, key)
dict字典类型会有该方法,它定义了key如果在容器中找不到时触发的行为。
比如d = {'a': 1}, 当你执行d[notexist]时,d.missing['notexist']就会被调用。


enter(self)
enter会返回一个值,并赋值给as关键词之后的变量。在这里,你可以定义代码段开始的一些操作。

exit(self, exception_type, exception_value, traceback)
exit定义了代码段结束后的一些操作,可以这里执行一些清除操作,或者做一些代码段结束后需要立即执行的命令,比如文件的关闭,socket断开等。如果代码段成功结束,那么exception_type, exception_value, traceback 三个参数传进来时都将为None。如果代码段抛出异常,那么传进来的三个参数将分别为: 异常的类型,异常的值,异常的追踪栈。
如果exit返回True, 那么with声明下的代码段的一切异常将会被屏蔽。
如果exit返回None, 那么如果有异常,异常将正常抛出,这时候with的作用将不会显现出来。


getinitargs(self)
如果你希望unpickle时,init方法能够调用,那么就需要定义getinitargs, 该方法需要返回一系列参数的元组,这些参数就是传给init的参数。

该方法只对old-style class有效。所谓old-style class,指的是不继承自任何对象的类,往往定义时这样表示: class A:, 而非class A(object):

getnewargs(self)
getinitargs很类似,只不过返回的参数元组将传值给new

getstate(self)
在调用pickle.dump时,默认是对象的dict属性被存储,如果你要修改这种行为,可以在getstate方法中返回一个state。state将在调用pickle.load时传值给setstate

setstate(self, state)
一般来说,定义了getstate,就需要相应地定义setstate来对getstate返回的state进行处理。

reduce(self)
如果pickle的数据包含了自定义的扩展类(比如使用C语言实现的Python扩展类)时,就需要通过实现reduce方法来控制行为了。由于使用过于生僻,这里就不展开继续讲解了。

令人容易混淆的是,我们知道, reduce()是Python的一个內建函数, 需要指出reduce并非定义了reduce()的行为,二者没有关系。

reduce_ex(self)
reduce_ex 是为了兼容性而存在的, 如果定义了reduce_ex, 它将代替reduce 执行。


比较运算符
cmp(self, other)
如果该方法返回负数,说明self < other; 返回正数,说明self > other; 返回0说明self == other。
强烈不推荐来定义cmp, 取而代之, 最好分别定义lt等方法从而实现比较功能。
cmp在Python3中被废弃了。

eq(self, other)
定义了比较操作符==的行为.

ne(self, other)
定义了比较操作符!=的行为.

lt(self, other)
定义了比较操作符<的行为.

gt(self, other)
定义了比较操作符>的行为.

le(self, other)
定义了比较操作符<=的行为.

ge(self, other)
定义了比较操作符>=的行为.

下面我们定义一种类型Word, 它会使用单词的长度来进行大小的比较, 而不是采用str的比较方式。
但是为了避免 Word('bar') == Word('foo') 这种违背直觉的情况出现,并没有定义eq, 因此Word会使用它的父类(str)中的eq来进行比较。


一元运算符和函数
pos(self)
实现了'+'号一元运算符(比如+some_object)

neg(self)
实现了'-'号一元运算符(比如-some_object)

invert(self)
实现了~号一元运算符(比如~some_object)

abs(self)
实现了abs()內建函数.

round(self, n)
实现了round()内建函数. 参数n表示四舍五进的精度.

floor(self)
实现了math.round(), 向下取整.

ceil(self)
实现了math.ceil(), 向上取整.

trunc(self)
实现了math.trunc(), 向0取整.

算术运算符
add(self, other)
实现了加号运算.

sub(self, other)
实现了减号运算.

mul(self, other)
实现了乘法运算.

floordiv(self, other)
实现了//运算符.

div(self, other)
实现了/运算符. 该方法在Python3中废弃. 原因是Python3中,division默认就是true division.

truediv(self, other)
实现了true division. 只有你声明了from future import division该方法才会生效.

mod(self, other)
实现了%运算符, 取余运算.

divmod(self, other)
实现了divmod()內建函数.

pow(self, other)
实现了**操作. N次方操作.

lshift(self, other)
实现了位操作<<.

rshift(self, other)
实现了位操作>>.

and(self, other)
实现了位操作&.

or(self, other)
实现了位操作|

xor(self, other)
实现了位操作^


类型转化
int(self)
实现了类型转化为int的行为.

long(self)
实现了类型转化为long的行为.

float(self)
实现了类型转化为float的行为.

complex(self)
实现了类型转化为complex(复数, 也即1+2j这样的虚数)的行为.

oct(self)
实现了类型转化为八进制数的行为.

hex(self)
实现了类型转化为十六进制数的行为.

index(self)


str(self)
对实例使用str()时调用。

repr(self)
对实例使用repr()时调用。str()和repr()都是返回一个代表该实例的字符串,
主要区别在于: str()的返回值要方便人来看,而repr()的返回值要方便计算机看。

unicode(self)
对实例使用unicode()时调用。unicode()与str()的区别在于: 前者返回值是unicode, 后者返回值是str。unicode和str都是basestring的子类。

当你对一个类只定义了str但没定义unicode时,unicode会根据str的返回值自动实现,即return unicode(self.str());
但返回来则不成立。


format(self, formatstr)
"Hello, {0:abc}".format(a)等价于format(a, "abc"), 等价于a.format("abc")。

这在需要格式化展示对象的时候非常有用,比如格式化时间对象。

hash(self)
对实例使用hash()时调用, 返回值是数值类型。

nonzero(self)
对实例使用bool()时调用, 返回True或者False。
你可能会问, 为什么不是命名为bool? 我也不知道。
我只知道该方法在Python3中改名为bool了。

dir(self)
对实例使用dir()时调用。通常实现该方法是没必要的。

sizeof(self)
对实例使用sys.getsizeof()时调用。返回对象的大小,单位是bytes。

instancecheck(self, instance)
对实例调用isinstance(instance, class)时调用。 返回值是布尔值。它会判断instance是否是该类的实例。

subclasscheck(self, subclass)
对实例使用issubclass(subclass, class)时调用。返回值是布尔值。它会判断subclass否是该类的子类。

copy(self)
对实例使用copy.copy()时调用。返回"浅复制"的对象。

deepcopy(self, memodict={})
对实例使用copy.deepcopy()时调用。返回"深复制"的对象。

Tags: 记录

添加新评论 »