Python 魔術方法(Magic Methods)完整指南 | Python
Python 的 魔術方法(Magic Methods),又稱為 雙底線方法(Dunder Methods),是一組以雙底線開頭和結尾的特殊方法。透過定義這些方法,你可以讓自定義的類別支援 Python 的內建操作,例如
print()、len()、算術運算等,讓你的程式碼更加 Pythonic。
什麼是魔術方法?
魔術方法是 Python 類別中以 __ 開頭和結尾的特殊方法,例如 __init__、__str__、__len__ 等。當你使用 Python 的內建功能時,Python 會在背後自動呼叫對應的魔術方法。
# 當你使用這些操作時,Python 其實在呼叫魔術方法
len([1, 2, 3]) # 呼叫 list.__len__()
str(42) # 呼叫 int.__str__()
1 + 2 # 呼叫 int.__add__(1, 2)
init 與 str
__init__ 是最常見的魔術方法,用於初始化物件。__str__ 則定義物件被 print() 或 str() 轉換時的顯示內容:
class Book:
def __init__(self, title, author, pages):
self.title = title
self.author = author
self.pages = pages
def __str__(self):
return f"《{self.title}》- {self.author}"
book = Book("Python 入門", "BenzHub", 300)
print(book) # 輸出:《Python 入門》- BenzHub
repr vs str
__repr__ 用於提供物件的「官方」字串表示,通常用於除錯,目標是產生一個能重建物件的表達式:
class Book:
def __init__(self, title, author, pages):
self.title = title
self.author = author
self.pages = pages
def __str__(self):
return f"《{self.title}》- {self.author}"
def __repr__(self):
return f"Book('{self.title}', '{self.author}', {self.pages})"
book = Book("Python 入門", "BenzHub", 300)
print(str(book)) # 輸出:《Python 入門》- BenzHub
print(repr(book)) # 輸出:Book('Python 入門', 'BenzHub', 300)
簡單來說,__str__ 給使用者看,__repr__ 給開發者看。
比較方法
透過定義比較魔術方法,讓物件可以使用 ==、<、> 等運算子:
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def __eq__(self, other):
return self.score == other.score
def __lt__(self, other):
return self.score < other.score
def __repr__(self):
return f"{self.name}({self.score})"
s1 = Student("Alice", 90)
s2 = Student("Bob", 85)
s3 = Student("Charlie", 90)
print(s1 == s3) # 輸出:True(分數相同)
print(s2 < s1) # 輸出:True(85 < 90)
算術方法
定義 __add__ 等方法,讓物件支援算術運算子:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
def __repr__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2) # 輸出:Vector(4, 6)
print(v1 * 3) # 輸出:Vector(3, 6)
len 與 getitem
__len__ 讓物件支援 len() 函式,__getitem__ 讓物件支援索引存取 []:
class Playlist:
def __init__(self, name, songs):
self.name = name
self.songs = songs
def __len__(self):
return len(self.songs)
def __getitem__(self, index):
return self.songs[index]
def __repr__(self):
return f"Playlist('{self.name}', {len(self)} 首歌)"
playlist = Playlist("我的最愛", ["歌曲A", "歌曲B", "歌曲C"])
print(len(playlist)) # 輸出:3
print(playlist[0]) # 輸出:歌曲A
print(playlist[-1]) # 輸出:歌曲C
# 因為定義了 __getitem__,還可以用 for 迴圈遍歷
for song in playlist:
print(song)
# 輸出:
# 歌曲A
# 歌曲B
# 歌曲C
實用範例:自定義金額類別
結合多個魔術方法,打造一個完整的自定義類別:
class Money:
def __init__(self, amount, currency="TWD"):
self.amount = amount
self.currency = currency
def __add__(self, other):
if self.currency != other.currency:
raise ValueError("幣別不同,無法相加")
return Money(self.amount + other.amount, self.currency)
def __eq__(self, other):
return self.amount == other.amount and self.currency == other.currency
def __lt__(self, other):
return self.amount < other.amount
def __str__(self):
return f"{self.currency} {self.amount:,.0f}"
def __repr__(self):
return f"Money({self.amount}, '{self.currency}')"
price1 = Money(1500)
price2 = Money(800)
total = price1 + price2
print(total) # 輸出:TWD 2,300
print(price1 > price2) # 輸出:True
總結
魔術方法 讓你的自定義類別能無縫融入 Python 的語法體系。透過定義 __str__、__repr__ 控制物件的顯示方式,使用 __eq__、__lt__ 實現比較運算,以及 __add__、__len__、__getitem__ 等方法支援各種內建操作。善用魔術方法,能讓你的程式碼更簡潔、更 Pythonic。希望這篇文章能幫助你掌握這些實用的特殊方法。
魔術方法是物件導向的進階應用,建議先閱讀 Python 的物件導向程式設計。若想了解如何透過繼承讓子類別繼承魔術方法,可以參考 Python 繼承與多型。