上一篇的 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__()
方法。
先用最簡單的例子看看 __getitem__()
方法的用法:
class Fib(object):
def __getitem__(self, n):
return n*n
測試:
>>> f = Fib()
>>> f[1]
1
>>> f[5]
25
接下來我們實現(xiàn)斐波拉契數(shù)列:
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
但是 Fib 還不能像 list
那樣使用切片操作鳍贾,原因是 __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ù)作處理骑科,也沒有對負數(shù)作處理,所以构拳,要正確實現(xiàn)一個 __getitem__()
還是有很多工作要做的咆爽。
此外,如果把對象看成 dict
置森,__getitem__()
的參數(shù)也可能是一個可以作 key
的 object
斗埂,例如 str
。
與之對應的是 __setitem__()
方法凫海,把對象視作 list
或 dict
來對集合賦值蜜笤。最后,還有一個 __delitem__()
方法盐碱,用于刪除某個元素把兔。
總之沪伙,通過上面的方法,我們自己定義的類表現(xiàn)得和 Python 自帶的 list
县好、tuple
围橡、dict
沒什么區(qū)別,這完全歸功于動態(tài)語言的“鴨子類型”缕贡,不需要強制繼承某個接口翁授。