python 中存在許多 Magic Methods (或 Dunder Methods),可以讓 Python 編程中的類 (class) 增添許多特殊的方法,通常左右被兩個底線所包圍 (__init__
, _lt_
等…)。
近期由於開始自學 Deep Learning,根據費曼學習法 (the Feynman Technique),快速學習一門學問快速的方式,其中兩步驟即是將所學知識內化並且輸出。於是乎透過筆記記錄下學習後所內化的基礎或理論知識。
__getitem__
對於 __getitem__
的解釋如下:
__getitem__
方法在 Python 中被用來定義方括號運算符 ([]
) 用在索引對象時的行為。透過 __getitem__
我們可以定義使用方括号 ([]
) 訪問對象的元素時應該發生什麼。
例如有一個類似列表的對象,透過使用__getitem__
方法來定義如何檢索特定索引處的元素,返回指定索引處的項目,如果索引超出邊界則返回異常。
class MyList:
def __init__(self, items):
self._items = items
def __getitem__(self, index):
return self._items[index]
my_list = MyList([1, 2, 3, 4, 5])
print(my_list[2]) # Output: 3
print(my_list[-1]) # Output: 5
程序回傳
>> 3
>> 5
__setitem__
__setitem__
方法在 Python 中被用來定義方括號運算符 ([]
) 用在對象中元素賦值的行為。也就是說我們可以自行定義當我用方括號運算符 ([]
) 賦值的方式。通常被用來設定字典 (dictionary) 中的鍵 (key) 與值 (value)。
例如當有個很像列表的對象,透過 __setitem__
方法我們可以定義兩個數據:索引、賦予的值。於是我們即可透過此方法對對象中特定索引的元素賦值。當然如果索引超出邊界或不合法的數值則會返回例外。
下面範例中,透過方括號運算符 ([]
) 對列表中編號 2 的數值重新賦值。
class MyList:
def __init__(self, items):
self._items = items
def __setitem__(self, index, value):
if index < 0 or index >= len(self._items):
raise IndexError("Index out of range")
self._items[index] = value
my_list = MyList([1, 2, 3, 4, 5])
my_list[2] = 10
print(my_list._items)
程序回傳
>> [1, 2, 10, 4, 5]
__len__
__len__
方法用來定義:在一個對象上調用 Python 內建 len() 函數時的行為。它允許你重新定義一個對象回傳的長度值。
例如下面範例中,將 __len__
方法中返回的值為數據長度值乘以 2。
class MyList:
def __init__(self, items):
self._items = items
def __len__(self):
return len(self._items) * 2
my_list = MyList([1, 2, 3, 4, 5])
print(len(my_list))
於是我們對對象 my_list
調用 len()
函數時則返回實際長度乘以 2。
>> 10
這節會透過幾個不同的範例加強對三種方法的應用與解釋。
下面範例我們將 __getitem__
定義為獲取字典中鍵 (key) 的值。此處用到 __setitem__
方法,將對象新增鍵 (key) 必且賦值 (value)。
在 Python 的字典中,每一個元素都由鍵 (key) 和值 (value) 構成,結構為 key: value。
class MyDict:
def __init__(self):
self._items = {}
def __getitem__(self, key):
return self._items.get(key)
def __setitem__(self, key, value):
self._items[key] = value
my_dict = MyDict()
my_dict['name'] = 'John'
my_dict['grade'] = 'Level B'
print(my_dict['name'])
print(my_dict['grade'])
print(my_dict['location'])
回傳數據如下,因為字典中並未新增 'location'
鍵 (key),所以返回 None
。
>> 'John'
>> 'Level B'
>> None
Python 中如果在類中定義了__getitem__
方法,則會被認為是可以迭代的,因此 for
循環中會不斷調用 __getitem__
方法,直到引發 IndexError 為止。此處用到 __len__
方法疊加在 For
迴圈中的結果中。
class MyRange:
def __init__(self, start, stop):
self._start = start
self._stop = stop
def __getitem__(self, index):
if index < 0:
index = self._stop + index
if index < len(self):
self.add = 3
else:
self.add = 0
if index < self._start or index >= self._stop:
raise IndexError("Index out of range")
return index + self.add
def __len__(self):
return 2
for number in MyRange(0, 5):
print(number)
print('--------')
print(len(MyRange(0, 5)))
回傳數據如下,因為在 MyRange
這個類當中定義了 len() 的行為為直接回傳數值 2,因此當我們在 __getitem__
方法中調用 len() 函數時,則會直接返回 2。
而當 For
迴圈在調用 __getitem__
方法時,迭代器會執行 MyRange[x]
,其中 x 會從 0 開始。
由於 MyRange[0]
與 MyRange[1]
都會使 if index < len(self):
成立,因此在前兩個輸出值會疊加 3 在輸出結果。
>> 3
>> 4
>> 2
>> 3
>> 4
>> --------
>> 2