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)

initstr

__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)

lengetitem

__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 繼承與多型