其他关于Python的总结文章请访问:https://www.jianshu.com/nb/47435944
详解Python类中的特殊方法(前后都有双下划线的方法)-len、str、getitem、iter、getattr、call等
类中定义的一些特殊方法,也就是方法名称前后都有双下划线标识的方法,都具有特殊的意义,重写这些方法可以帮助类更好地发挥功能,这里主要介绍几种常用的、重要的方法。
我们以一个偶数类(Even
)为例,其中会创建一个N个偶数的列表,同时创建一个该类的实例even
:
class Even:
def __init__(self, N):
self.N = N
self.even_list = [2 * x for x in range(N)]
even = Even(10)
len方法
__len__
方法在当 len
函数作用于该类的时候被调用,比如我们定义Even
类的长度就是偶数列表的个数:
def __len__(self):
return self.N
此时调用len
函数作用于Even
类的实例上就会调用 __len__
方法:
print(len(even)) # 20
如果没有定义 __len__
方法,当len
函数作用于类的实例上时就会报错:
TypeError: object of type 'Even' has no len()
str方法
__str__
方法在当 print
函数作用于该类的时候被调用,比如我们继续编写Even
类,加入__str__
方法:
def __str__(self):
return "An Even Numbers List with {} Items:\n{}".format(self.N, self.even_list)
此时调用 print(even)
就可以得到如下的结果:
An Even Numbers List with 10 Items:
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
repr方法
__repr__
方法是在直接(比如解释器中)直接调用类或者实例时被触发的,它和__str__
很像,唯一不同的是没有print
操作,比如这样调用时会触发 __repr__
(Python解释器中):
>>> even
(注意上边跟 >>> print(even)
的区别)
一般来说__repr__
方法和__str__
方法输出的内容相同,所以通常可以使用简单的方式来定义__repr__
方法:
__repr__ = __str__
getitem方法
__getitem__
方法在对类进行迭代时触发,而且必须传入一个整数作为参数:
def __getitem__(self, n):
return self.even_list[n]
这样就可以使用for
循环进行对Even
类的遍历了,或者使用 even[i]
这样对Even
类进行索引,甚至是使用切片:
for i in range(len(even)):
print(even[i], end=' ')
print()
for e in even:
print(e, end=' ')
print()
print(even[2:8])
print(even[8:2:-1])
可以得到输出结果:
0 2 4 6 8 10 12 14 16 18
0 2 4 6 8 10 12 14 16 18
[4, 6, 8, 10, 12, 14]
[16, 14, 12, 10, 8, 6]
setitem方法
__setitem__
方法是和__getitem__
方法对应的,用来更改某下标所对应处的值,必须传入两个参数,一个key
用于指定要修改的下标,一个value
用于告知要修改的值:
def __setitem__(self, key, value):
self.even_list[key] = value
这样就可以修改类的某个索引处的值了:
print(even[0]) # 0
even[0] = 100
print(even[0]) # 100
delitem方法
__delitem__
方法实现了del
作用于类时的逻辑:
def __delitem__(self, key):
del self.even_list[key]
self.N = len(self.even_list)
这样使用 del
作用与类就可以得到相应的结果:
print(even)
del even[0:5]
print(even)
得到的结果:
An Even Numbers List with 10 Items:
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
An Even Numbers List with 5 Items:
[10, 12, 14, 16, 18]
iter方法和next方法
__iter__
方法返回一个可迭代对象,供 for ... in ...
循环对类进行迭代,同时配合__next__
方法在对类使用 next
函数时调用获取下一个迭代值,并且 __next__
方法中可以实现迭代结束后给出 StopIteration
错误的逻辑。
getattr方法
__getattr__
方法在类的实例试图调用一个不存在的属性时触发,可以对应地返回一个属性值或者函数,也可以完成对于一些属性抛出错误的逻辑:
def __getattr__(self, item):
if item == 'length':
return self.N
if item == 'get_length':
return lambda: self.N
raise AttributeError("Even doesn't have the attribute {}".format(item))
此时如果这样使用类,就会得到相应的结果:
print(even.length) # 10
print(even.get_length()) # 10
print(even.some_other_attribute) # AttributeError: Even doesn't have the attribute some_other_attribute
注意该方法只会处理调用不存在的属性的情况,如果属性存在则不会到__getattr__
方法中寻找
call方法
__call__
方法在类的实例被调用的时候触发,还可以接收参数,我们可以使用callable
函数来判断一个类的实例是不是可调用的,callable
一个没有定义__call__
方法的类的实例会返回False
,反之返回True
:
def __call__(self):
print("Hello, you called me: an even numbers list with {} items".format(self.N))
此时调用该类的实例:
even()
print(callable(even))
就会得到相应的结果:
Hello, you called me: an even numbers list with 10 items
True
上述内容的完整类的代码
class Even:
def __init__(self, N):
self.N = N
self.even_list = [2 * x for x in range(N)]
def __len__(self):
return self.N
def __str__(self):
return "An Even Numbers List with {} Items:\n{}".format(self.N, self.even_list)
__repr__ = __str__
def __getitem__(self, n):
return self.even_list[n]
def __setitem__(self, key, value):
self.even_list[key] = value
def __delitem__(self, key):
del self.even_list[key]
self.N = len(self.even_list)
def __getattr__(self, item):
if item == 'length':
return self.N
if item == 'get_length':
return lambda: self.N
raise AttributeError("Even doesn't have the attribute {}".format(item))
def __call__(self):
print("Hello, you called me: an even numbers list with {} items".format(self.N))