#Python_Magic Methods: getitem, setitem, len 的說明與範例

A. Magic or Dunder Methods

前言

python 中存在許多 Magic Methods (或 Dunder Methods),可以讓 Python 編程中的類 (class) 增添許多特殊的方法,通常左右被兩個底線所包圍 (__init__, _lt_ 等…)。

近期由於開始自學 Deep Learning,根據費曼學習法 (the Feynman Technique),快速學習一門學問快速的方式,其中兩步驟即是將所學知識內化並且輸出。於是乎透過筆記記錄下學習後所內化的基礎或理論知識。

A.1 __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

A.2 __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]

A.3 __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

B. 綜合範例

這節會透過幾個不同的範例加強對三種方法的應用與解釋。

B.1 字典

下面範例我們將 __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

B.2 迭代

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
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值