6.1 魔法方法
在Python中,操作符重載允許為自定義類別定義或更改內建操作符(例如,+, -, *, /)的行為。 這是通過特殊的方法,也稱為魔法方法來實現的。
例如,你可以在自己的類別中重載比較操作符:
| 操作符 | 無底線的方法 | 方法簽名 |
|---|---|---|
| == | eq() |
__eq__(self, other) |
| != | ne() |
__ne__(self, other) |
| < | lt() |
__lt__(self, other) |
| <= | le() |
__le__(self, other) |
| > | gt() |
__gt__(self, other) |
| >= | ge() |
__ge__(self, other) |
假設你編寫了一個類別,並想讓你的類別物件以你需要的方式進行比較。你只需在你的類別中實現「__eq__」方法,Python就會在每次代碼中比較你的類別物件時調用它。
示例:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
# 使用
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(4, 5)
print(v1 == v2) # 輸出: True
print(v1 == v3) # 輸出: False
每當你比較兩個您的物件時,Python會檢查他們是否實現了 函數 「__eq__」。如果有,就會調用它。如果沒有,則只是比較物件的引用。
實際上,上面的示例是寫著(只是還需加上檢查方法存在的句子):
# 使用
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(4, 5)
print(v1.__eq__(v2)) # 輸出: True
print(v1.__eq__(v3)) # 輸出: False
6.2 所有操作符列表
總共有6组操作符可以重載。
算術操作符:
| 操作符 | 無底線的方法 | 方法簽名 |
|---|---|---|
| + | add |
__add__(self, other) |
| - | sub |
__sub__(self, other) |
| * | mul |
__mul__(self, other) |
| / | truediv |
__truediv__(self, other) |
| // | floordiv |
__floordiv__(self, other) |
| % | mod |
__mod__(self, other) |
| ** | pow |
__pow__(self, other) |
比較操作符:
| 操作符 | 無底線的方法 | 方法簽名 |
|---|---|---|
| == | eq |
__eq__(self, other) |
| != | ne |
__ne__(self, other) |
| < | lt |
__lt__(self, other) |
| <= | le |
__le__(self, other) |
| > | gt |
__gt__(self, other) |
| >= | ge |
__ge__(self, other) |
邏輯操作符:
| 操作符 | 無底線的方法 | 方法簽名 |
|---|---|---|
| & | and |
__and__(self, other) |
| | | or |
__or__(self, other) |
| ^ | xor |
__xor__(self, other) |
| ~ | invert |
__invert__(self) |
索引和切片操作符:
| 操作符 | 方法 |
|---|---|
| obj[key] | __getitem__(self, key) |
| obj[key] = value | __setitem__(self, key, value) |
| del obj[key] | __delitem__(self, key) |
一元操作符:
| 操作符 | 方法 |
|---|---|
| - | __neg__(self) |
| + | __pos__(self) |
| abs() | __abs__(self) |
| ~ | __invert__(self) |
賦值操作符:
| 操作符 | 方法 |
|---|---|
| += | __iadd__(self, other) |
| -= | __isub__(self, other) |
| *= | __imul__(self, other) |
| /= | __itruediv__(self, other) |
| //= | __ifloordiv__(self, other) |
| %= | __imod__(self, other) |
| **= | __ipow__(self, other) |
可能這就是為什麼Python這麼慢 - 每次執行操作符之前,它都在查找類別及其所有父類別中的類似函數。不過這也使得代碼非常簡潔 :)
6.3 索引操作符
能夠比較物件或減去集合在某種意義上是顯而易見的。如果你編寫一個類別,並且這個類別預期會進行邏輯或數學運算,那麼你很容易想到這一點。
我想和你們分享一個有趣的例子——索引操作符。我們直接從示例代碼開始吧:
class CustomList:
def __init__(self, data):
self.data = data
def __getitem__(self, index):
return self.data[index]
def __setitem__(self, index, value):
self.data[index] = value
def __delitem__(self, index):
del self.data[index]
def __repr__(self):
return repr(self.data)
# 使用
c_list = CustomList([1, 2, 3, 4, 5])
print(c_list[1]) # 輸出: 2
c_list[1] = 10
print(c_list) # 輸出: [1, 10, 3, 4, 5]
del c_list[1]
print(c_list) # 輸出: [1, 3, 4, 5]
這裡我們看到三個操作的示例:
通過索引讀取數據通過索引寫入數據甚至通過索引刪除數據。
而且內部的數據完全不必以列表的形式存儲。或者說索引不一定非得是數字。例如,類別dictionary(字典)就是這樣實現的。
創建SuperList
還記得類別list嗎?它允許你設置元素,但僅限於已有的索引。我們來創建一個自己的類別,叫做SuperList,這個類別可以用任何索引訪問元素:
如果索引小於0,則將元素插入到開頭如果索引大於等於len,則將元素添加到末尾其餘情況下,只是返回該元素
示例:
class SuperList(list):
def __init__(self, value):
super().__init__(value)
def __setitem__(self, index, value):
if index >= len(self):
super().append(value)
elif index < 0:
super().insert(0, value)
else:
super().__setitem__(index, value)
lst = SuperList([1, 2, 3])
lst[200] = 100
lst[-200] = 99
print(lst) # [99, 1, 2, 3, 100]
所以,重載索引是一個很棒的功能,我建議在實踐中好好利用它。那麼今天就到這裡。
GO TO FULL VERSION