Python——特殊方法,, Python中以
Python——特殊方法,, Python中以
Python中以双下划线开头和结尾的函数称为特殊函数,对于实例执行一些特定的运算时,Python会自动视图调用这些实例的特殊方法,从而在Python中可以很轻易地实现运算符的重载。
Python中有一些通用的特殊函数:
1. 初始化与终止化
__new__(cls[, args...])
__new__()是一个静态方法,用于根据类型创建实例。Python在调用__new__()方法获得实例后,会调用这个实例的__init__()方法,然后将最初传给__new__()方法的参数都传给__init__()方法。
__init__()
__init__()是一个实例方法,用来在实例创建完成后进行必要的初始化,该方法必须返回None.
Python不会自动调用父类的__init__()方法,这需要额外的调用:
super(C, self).__init__()
来完成。
__del__(self)
在GC之前,Python会调用这个对象的__del__()方法完成一些终止化工作。如果没有__del__()方法,那么Python不做特殊的处理;
Python无视__del__()方法的返回值;
Python不会自动调用父类的__del__()方法,除非显式调用;
定义了__del__()方法的实例无法参与到循环GC中,所以对于这样的实例应该避免循环引用;
try/finally语句或with语句可能是比__del__()更好的方式。
2. 表现形式
__repr__(self)
Python内置的repr()函数,`x`表达式形式,或者交互式解释器在显示一个表达式语句的结果时,都调用这个对象的__repr__()方法;
__repr__()方法返回的字符串主要是面向解释器的,改写的话应该满足:eval(repr(x)) == x。
如果没有定义__repr__(),那么Python使用一种默认的表现形式。
__str__(self)
Python内置的1. str()函数,2. print(x)语句,都会调用对象的__str__()方法;
与__repr__()返回的详尽的、准确的、无歧义的对象描述字符串不同,__str__()方法只是返回一个对应对象的简洁的字符串表达形式;
当__str__()缺失时,Python会调用__repr__()方法;
__str__()返回的字符串应该是面向用户的,可读的。
__unicode__(self)
Python内置的unicode(x)方法会调用__unicode__()方法;
该方法如果定义,优先级高于__str__()方法;
同时定义这两个方法的实例,调用它们的结果应该相同。
3. 比较、哈希与布尔值
__lt__(self, other)
x<y 运算将会调用实例x的__lt__(self, other)方法;
__le__(self, other)
x<=y 运算将会调用实例x的__le__(self, other)方法;
__gt__(self, other)
x>y 运算将会调用实例x的__gt__(self, other)方法;
__ge__(self, other)
x>=y 运算将会调用实例x的__ge__(self, other)方法;
__eq__(self, other)
x==y 运算将会调用实例x的__eq__(self, other)方法;
__ne__(self, other)
x!=y 运算将会调用实例x的__ne__(self, other)方法;
*上述用于实例间比较的特殊方法应该返回True或False,或者返回NotImplemented来告诉Python解释器使用其他的方式进行比较。
__cmp__(self, other)
对于上面提到的比较操作,如果对应的特殊方法没有定义或者返回NotImplemented,则会调用__cmp__(self, other)再进行一次尝试;
一些内置的方法:cmp(x, y), max(x, y)或者列表对象的sort()方法也会调用__cmp__()方法;
实现x.__cmp__()方法时,如果x小于y,应该返回-1,如果x大于y,应该返回1;如果x等于y,应该返回0.
对于序列化比较(<, <=, >=, >),如果最终__cmp__()也没有定义,那么会抛出异常;
对于相等与否的比较(==, !=),如果最终__cmp__()也没有定义,将会变成身份检验:判断id(x) == id(y)是否成立。
__hash__(self)
三种情形会调用__hash__()方法:1. 内置的hash()方法,2.作为字典的键时,3.作为集合的成员时;
__hash__()方法应该返回一个32位长的整数,对与同一个对象,__hash__()方法应该总是返回相同的值;对于x == y,即使二者不属于相同的类型,只要他们是可哈希的(hashable),都应该确保得到hash(x) == hash(y);
没有__hash__()方法,也没有__cmp__()和__eq__()方法,上面提到的三种情形将使用id(x)作为替代;
没有__hash__()方法,但是有__cmp__()和__eq__()方法,上面提到的前两种方法会抛出异常;
通常只为同时定义了__cmp__()和/或__eq__()方法的不可变(immutable)对象定义__hash__()方法,
__nonzero__(self)
判断一个对象是为真还是假时,例如调用bool(x)方法时,Python会调用x.__nonzero__(self)方法,__nonzero__()方法应该返回True或False。
如果实例没有__nonzero__()方法,那么Python会调用实例的__len__()方法,当__len__()方法返回0时,Python认为该对象为假。所以如果实例没有__nonzero__()方法与__len__()方法,则Python认为该实例总是真的;
*所以以一个容器是否非空为判断条件时,应该写成:
if container: pass
而不是:
if len(container) > 0 : pass
因为后者将错过__nonzero__()方法的检验。
4. 属性的引用、绑定与解绑定
__getattribute__(self, name)
访问对象的属性x.y时,Python会自动调用x.__getattribute__(‘y‘)方法;
__getattribute__()方法应该返回被访问的属性的值或者是抛出异常AttributeError;
覆写类型的__getattribute__()方法会导致实例的属性访问变慢。
__getattr__(self, name)
当常规的属性访问(x.__class__或x.__dict__的键访问)无法找到目标属性时,Python会调用__getattr__()方法;
如果该方法没能找到目标属性,应该抛出AttributeError。
__setattr__(self, name, value)
绑定实例的某个属性(赋值),例如x.y = value时,Python会自动调用x.__setattr__(‘y‘, value)方法;
Python无视__setattr__()方法的返回值;
如果没有定义__setattr__()方法,Python将赋值x.y = value解释成x.__dict__[‘y‘] = value。
__delattr__(self, name)
当解绑定一个对象的某个属性(例如调用del x.y)时,会调用x.__delattr__(‘y‘)方法;
Python无视__delattr__()方法的返回值;
如果没有定义__delattr__()方法,那么Python将del x.y解释成del x.__dict__[‘y‘]。
5. 可调用对象
__call__(self[, args...])
定义了该方法的对象可以像函数那样被调用,因此被称为可调用对象。
二 、容器的特殊方法
容器可以是 序列(sequence) 或者 映射(mapping)
__contains__(self, item)
布尔测试y in x会调用x.__contains__(y);
对于序列x而言,如果y等于x中的某一个值,那么__contains__()方法应该返回True;
对于映射x而言,如果y等于x的键中的某一个,那么__contains__()方法应该返回True;
如果没有定义__contains__()方法,那么测试y in x等价于:
for z in x: if y == z: return True else: return False
__delitem__(self, key)
从容器中解绑一个项或者切片(如del x[key])将会调用x.__delitem__(key)方法,
只有可变对象才应该定义这个方法。
__getitem__(self, key)
调用x[key](索引或切片)时将会调用x.__getitem__(key)方法;
__iter__(self)
对于试图遍历一个容器的全部元素的请求(例如for i in x),Python将会调用x.__iter__()来获得x上的一个迭代器;
Python内置函数iter(x)也会调用x.__iter__()方法;
如果没有定义__iter__()方法,那么iter(x)方法会合成并返回一个包含x的新的迭代器,然后逐个返回x中的元素;
最好在每个容器中都实现__iter__()方法。
__len__(self)
Python内置的len(x)调用或其他试图得知x中的元素个数的函数都会最终调用x.__len__();
__len__()方法应该返回整形的数值;
没有定义__nonzero__()时,Python也会调用__len__()方法来判断容器的真假;
容器都应该定义__len__()方法,除非实现起来特别昂贵的情形。
__setitem__(self, key, value)
对容器的一个元素或切片进行绑定(如:x[key] = value)时,Python会调用x.__setitem__(key, value);
可变(mutable)容器才应该定义该方法。
Python——特殊方法
相关内容
- 暂无相关文章
评论关闭