講解對象:__getitem__ --python按照下標取出元素
作者:融水公子 rsgz
__getitem__
Fib實例雖然能作用于for循環(huán),看起來和list有點像但是,把它當成list來使用還是不行,比如,取第5個元素:
Fib()[5]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'Fib' object does not support indexing
要表現(xiàn)得像list那樣按照下標取出元素,需要實現(xiàn)__getitem__()方法:
class Fib(object):
def __getitem__(self, n):
a, b = 1, 1
for x in range(n):
a, b = b, a + b
return a
現(xiàn)在,就可以按下標訪問數(shù)列的任意一項了:
f = Fib()
f[0]
1
f[1]
1
f[2]
2
f[3]
3
f[10]
89
f[100]
573147844013817084101
但是list有個神奇的切片方法:
list(range(100))[5:10]
[5, 6, 7, 8, 9]
對于Fib卻報錯。原因是__getitem__()傳入的參數(shù)可能是一個int,也可能是一個切片對象slice,所以要做判斷:
class Fib(object):
def __getitem__(self, n):
if isinstance(n, int): # n是索引
a, b = 1, 1
for x in range(n):
a, b = b, a + b
return a
if isinstance(n, slice): # n是切片
start = n.start
stop = n.stop
if start is None:
start = 0
a, b = 1, 1
L = []
for x in range(stop):
if x >= start:
L.append(a)
a, b = b, a + b
return L
現(xiàn)在試試Fib的切片:
f = Fib()
f[0:5]
[1, 1, 2, 3, 5]
f[:10]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
但是沒有對step參數(shù)作處理:
f[:10:2]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
也沒有對負數(shù)作處理,所以,要正確實現(xiàn)一個__getitem__()還是有很多工作要做的。
此外,如果把對象看成dict,__getitem__()的參數(shù)也可能是一個可以作key的object,例如str。
與之對應(yīng)的是__setitem__()方法,把對象視作list或dict來對集合賦值。最后,還有一個__delitem__()方法,用于刪除某個元素。
總之,通過上面的方法,我們自己定義的類表現(xiàn)得和Python自帶的list、tuple、dict沒什么區(qū)別,這完全歸功于動態(tài)語言的“鴨子類型”,不需要強制繼承某個接口。