其他關(guān)于Python的總結(jié)文章請(qǐng)?jiān)L問:http://www.reibang.com/nb/47435944
詳解Python類中的特殊方法(前后都有雙下劃線的方法)-len茬斧、str、getitem梗逮、iter项秉、getattr、call等
類中定義的一些特殊方法库糠,也就是方法名稱前后都有雙下劃線標(biāo)識(shí)的方法伙狐,都具有特殊的意義涮毫,重寫這些方法可以幫助類更好地發(fā)揮功能,這里主要介紹幾種常用的贷屎、重要的方法罢防。
我們以一個(gè)偶數(shù)類(Even
)為例,其中會(huì)創(chuàng)建一個(gè)N個(gè)偶數(shù)的列表唉侄,同時(shí)創(chuàng)建一個(gè)該類的實(shí)例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__
方法在當(dāng) len
函數(shù)作用于該類的時(shí)候被調(diào)用咒吐,比如我們定義Even
類的長(zhǎng)度就是偶數(shù)列表的個(gè)數(shù):
def __len__(self):
return self.N
此時(shí)調(diào)用len
函數(shù)作用于Even
類的實(shí)例上就會(huì)調(diào)用 __len__
方法:
print(len(even)) # 20
如果沒有定義 __len__
方法,當(dāng)len
函數(shù)作用于類的實(shí)例上時(shí)就會(huì)報(bào)錯(cuò):
TypeError: object of type 'Even' has no len()
str方法
__str__
方法在當(dāng) print
函數(shù)作用于該類的時(shí)候被調(diào)用属划,比如我們繼續(xù)編寫Even
類恬叹,加入__str__
方法:
def __str__(self):
return "An Even Numbers List with {} Items:\n{}".format(self.N, self.even_list)
此時(shí)調(diào)用 print(even)
就可以得到如下的結(jié)果:
An Even Numbers List with 10 Items:
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
repr方法
__repr__
方法是在直接(比如解釋器中)直接調(diào)用類或者實(shí)例時(shí)被觸發(fā)的,它和__str__
很像同眯,唯一不同的是沒有print
操作绽昼,比如這樣調(diào)用時(shí)會(huì)觸發(fā) __repr__
(Python解釋器中):
>>> even
(注意上邊跟 >>> print(even)
的區(qū)別)
一般來說__repr__
方法和__str__
方法輸出的內(nèi)容相同,所以通承胛希可以使用簡(jiǎn)單的方式來定義__repr__
方法:
__repr__ = __str__
getitem方法
__getitem__
方法在對(duì)類進(jìn)行迭代時(shí)觸發(fā)硅确,而且必須傳入一個(gè)整數(shù)作為參數(shù):
def __getitem__(self, n):
return self.even_list[n]
這樣就可以使用for
循環(huán)進(jìn)行對(duì)Even
類的遍歷了,或者使用 even[i]
這樣對(duì)Even
類進(jìn)行索引明肮,甚至是使用切片:
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])
可以得到輸出結(jié)果:
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__
方法對(duì)應(yīng)的菱农,用來更改某下標(biāo)所對(duì)應(yīng)處的值,必須傳入兩個(gè)參數(shù)柿估,一個(gè)key
用于指定要修改的下標(biāo)循未,一個(gè)value
用于告知要修改的值:
def __setitem__(self, key, value):
self.even_list[key] = value
這樣就可以修改類的某個(gè)索引處的值了:
print(even[0]) # 0
even[0] = 100
print(even[0]) # 100
delitem方法
__delitem__
方法實(shí)現(xiàn)了del
作用于類時(shí)的邏輯:
def __delitem__(self, key):
del self.even_list[key]
self.N = len(self.even_list)
這樣使用 del
作用與類就可以得到相應(yīng)的結(jié)果:
print(even)
del even[0:5]
print(even)
得到的結(jié)果:
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__
方法返回一個(gè)可迭代對(duì)象,供 for ... in ...
循環(huán)對(duì)類進(jìn)行迭代秫舌,同時(shí)配合__next__
方法在對(duì)類使用 next
函數(shù)時(shí)調(diào)用獲取下一個(gè)迭代值的妖,并且 __next__
方法中可以實(shí)現(xiàn)迭代結(jié)束后給出 StopIteration
錯(cuò)誤的邏輯。
getattr方法
__getattr__
方法在類的實(shí)例試圖調(diào)用一個(gè)不存在的屬性時(shí)觸發(fā)足陨,可以對(duì)應(yīng)地返回一個(gè)屬性值或者函數(shù)羔味,也可以完成對(duì)于一些屬性拋出錯(cuò)誤的邏輯:
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))
此時(shí)如果這樣使用類,就會(huì)得到相應(yīng)的結(jié)果:
print(even.length) # 10
print(even.get_length()) # 10
print(even.some_other_attribute) # AttributeError: Even doesn't have the attribute some_other_attribute
注意該方法只會(huì)處理調(diào)用不存在的屬性的情況钠右,如果屬性存在則不會(huì)到__getattr__
方法中尋找
call方法
__call__
方法在類的實(shí)例被調(diào)用的時(shí)候觸發(fā),還可以接收參數(shù)忘蟹,我們可以使用callable
函數(shù)來判斷一個(gè)類的實(shí)例是不是可調(diào)用的飒房,callable
一個(gè)沒有定義__call__
方法的類的實(shí)例會(huì)返回False
,反之返回True
:
def __call__(self):
print("Hello, you called me: an even numbers list with {} items".format(self.N))
此時(shí)調(diào)用該類的實(shí)例:
even()
print(callable(even))
就會(huì)得到相應(yīng)的結(jié)果:
Hello, you called me: an even numbers list with 10 items
True
上述內(nèi)容的完整類的代碼
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))