從入門(mén)到精通的Python魔術(shù)方法(Magic Methods)完全指南
本文全面介紹了Python中特殊的魔術(shù)方法,這些以雙下劃線開(kāi)頭和結(jié)尾的方法(如__init__)為類(lèi)提供了"魔法"般的行為。主要內(nèi)容包括:
基礎(chǔ)知識(shí):魔術(shù)方法由Python自動(dòng)調(diào)用,用于實(shí)現(xiàn)各種內(nèi)置操作,如對(duì)象初始化(init)、字符串表示(str, repr)等。
核心分類(lèi):
- 對(duì)象生命周期方法(new, del)
- 比較運(yùn)算符(eq, __lt__等)
- 算術(shù)運(yùn)算(add, __mul__等)
- 容器模擬(len, __getitem__等)
實(shí)際應(yīng)用:通過(guò)豐富的代碼示例展示了如何利用魔術(shù)方法實(shí)現(xiàn)自定義類(lèi)的高級(jí)行為,如向量運(yùn)算、購(gòu)物車(chē)容器等。
魔術(shù)方法使Python的面向?qū)ο缶幊谈訌?qiáng)大和靈活,是構(gòu)建專(zhuān)業(yè)級(jí)Python類(lèi)的關(guān)鍵工具。
魔術(shù)方法(Magic Methods)是Python面向?qū)ο缶幊讨械奶厥夥椒?,它們賦予類(lèi)"魔法"般的行為。本文將全面解析Python中的魔術(shù)方法,通過(guò)豐富的示例和實(shí)際應(yīng)用場(chǎng)景,帶你深入理解這一重要概念。
一、魔術(shù)方法基礎(chǔ)
1. 什么是魔術(shù)方法
魔術(shù)方法是以雙下劃線開(kāi)頭和結(jié)尾的特殊方法(如__init__),Python會(huì)在特定時(shí)機(jī)自動(dòng)調(diào)用它們。它們不是用來(lái)直接調(diào)用的,而是讓類(lèi)能夠支持Python的各種內(nèi)置操作。
class MyClass:
def __init__(self, value):
self.value = value
def __str__(self):
return f"MyClass with value: {self.value}"
obj = MyClass(42)
print(obj) # 自動(dòng)調(diào)用__str__: "MyClass with value: 42"
2. 魔術(shù)方法的特點(diǎn)
- 命名規(guī)則:雙下劃線開(kāi)頭和結(jié)尾,如
__method__ - 自動(dòng)調(diào)用:由Python解釋器在特定情況下調(diào)用
- 豐富功能:實(shí)現(xiàn)運(yùn)算符重載、對(duì)象生命周期控制等
- 性能優(yōu)化:比普通方法調(diào)用更快(直接由解釋器處理)
二、常用魔術(shù)方法分類(lèi)詳解
1. 對(duì)象創(chuàng)建與初始化
| 方法 | 調(diào)用時(shí)機(jī) | 典型用途 |
|---|---|---|
| __new__ | 創(chuàng)建實(shí)例時(shí) | 控制實(shí)例創(chuàng)建過(guò)程(單例模式等) |
| __init__ | 初始化實(shí)例時(shí) | 設(shè)置初始屬性 |
| __del__ | 對(duì)象銷(xiāo)毀時(shí) | 清理資源 |
class Resource:
def __new__(cls, *args, **kwargs):
print("__new__ called - creating instance")
instance = super().__new__(cls)
return instance
def __init__(self, name):
print("__init__ called - initializing")
self.name = name
def __del__(self):
print(f"__del__ called - cleaning up {self.name}")
res = Resource("File") # 輸出: __new__ called → __init__ called
del res # 輸出: __del__ called
2. 對(duì)象表示與字符串轉(zhuǎn)換
| 方法 | 調(diào)用時(shí)機(jī) | 區(qū)別 |
|---|---|---|
| __str__ | str(obj), print(obj) | 用戶友好的字符串表示 |
| __repr__ | repr(obj), 交互式環(huán)境 | 明確的、可eval的表示 |
| __format__ | format(obj), f-string | 自定義格式化輸出 |
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"({self.x}, {self.y})"
def __repr__(self):
return f"Point({self.x}, {self.y})"
def __format__(self, format_spec):
if format_spec == 'r':
return f"{self.x}×{self.y}"
return str(self)
p = Point(3, 4)
print(str(p)) # (3, 4)
print(repr(p)) # Point(3, 4)
print(f"{p}") # (3, 4)
print(f"{p:r}") # 3×4
3. 比較運(yùn)算符重載
| 方法 | 對(duì)應(yīng)運(yùn)算符 |
|---|---|
| __lt__ | < |
| __le__ | <= |
| __eq__ | == |
| __ne__ | != |
| __gt__ | > |
| __ge__ | >= |
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 __le__(self, other):
return self.score <= other.score
alice = Student("Alice", 85)
bob = Student("Bob", 90)
print(alice < bob) # True
print(alice == bob) # False
4. 算術(shù)運(yùn)算符重載
| 方法 | 對(duì)應(yīng)運(yùn)算符 | 反向方法 |
|---|---|---|
| __add__ | + | __radd__ |
| __sub__ | - | __rsub__ |
| __mul__ | * | __rmul__ |
| __truediv__ | / | __rtruediv__ |
| __floordiv__ | // | __rfloordiv__ |
| __mod__ | % | __rmod__ |
| __pow__ | ** | __rpow__ |
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):
if isinstance(scalar, (int, float)):
return Vector(self.x * scalar, self.y * scalar)
return NotImplemented
def __rmul__(self, scalar):
return self.__mul__(scalar)
def __str__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(2, 3)
v2 = Vector(5, 7)
print(v1 + v2) # Vector(7, 10)
print(v1 * 3) # Vector(6, 9)
print(2 * v1) # Vector(4, 6) (調(diào)用__rmul__)
5. 容器類(lèi)型模擬
| 方法 | 用途 |
|---|---|
| __len__ | len(obj) |
| __getitem__ | obj[key] |
| __setitem__ | obj[key] = value |
| __delitem__ | del obj[key] |
| __contains__ | item in obj |
| __iter__ | 迭代對(duì)象時(shí) |
class ShoppingCart:
def __init__(self):
self.items = []
def __len__(self):
return len(self.items)
def __getitem__(self, index):
return self.items[index]
def __setitem__(self, index, value):
self.items[index] = value
def __delitem__(self, index):
del self.items[index]
def __contains__(self, item):
return item in self.items
def __iter__(self):
return iter(self.items)
def add(self, item):
self.items.append(item)
cart = ShoppingCart()
cart.add("蘋(píng)果")
cart.add("香蕉")
cart.add("橙子")
print(len(cart)) # 3
print(cart[1]) # 香蕉
print("蘋(píng)果" in cart) # True
for item in cart: # 迭代
print(item)
6. 上下文管理器
| 方法 | 調(diào)用時(shí)機(jī) |
|---|---|
| __enter__ | 進(jìn)入with塊時(shí) |
| __exit__ | 退出with塊時(shí) |
class Timer:
def __enter__(self):
import time
self.start = time.time()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
import time
self.end = time.time()
print(f"耗時(shí): {self.end - self.start:.2f}秒")
def elapsed(self):
return self.end - self.start
with Timer() as t:
# 執(zhí)行一些操作
sum(range(1000000))
# 自動(dòng)輸出: 耗時(shí): x.xx秒
7. 可調(diào)用對(duì)象
| 方法 | 調(diào)用時(shí)機(jī) |
|---|---|
| __call__ | obj()形式調(diào)用時(shí) |
class Adder:
def __init__(self, n):
self.n = n
def __call__(self, x):
return self.n + x
add5 = Adder(5)
print(add5(3)) # 8 (實(shí)例像函數(shù)一樣調(diào)用)
三、高級(jí)魔術(shù)方法
1. 屬性訪問(wèn)控制
| 方法 | 調(diào)用時(shí)機(jī) |
|---|---|
| __getattr__ | 訪問(wèn)不存在的屬性時(shí) |
| __getattribute__ | 訪問(wèn)任何屬性時(shí) |
| __setattr__ | 設(shè)置屬性時(shí) |
| __delattr__ | 刪除屬性時(shí) |
class AttributeLogger:
def __init__(self):
self.data = {}
def __getattr__(self, name):
print(f"訪問(wèn)不存在的屬性: {name}")
return None
def __setattr__(self, name, value):
print(f"設(shè)置屬性: {name} = {value}")
super().__setattr__(name, value)
def __delattr__(self, name):
print(f"刪除屬性: {name}")
super().__delattr__(name)
obj = AttributeLogger()
obj.x = 10 # 設(shè)置屬性: x = 10
print(obj.x) # 10
print(obj.y) # 訪問(wèn)不存在的屬性: y → None
del obj.x # 刪除屬性: x
2. 描述符協(xié)議
| 方法 | 調(diào)用時(shí)機(jī) |
|---|---|
| __get__ | 獲取描述符值時(shí) |
| __set__ | 設(shè)置描述符值時(shí) |
| __delete__ | 刪除描述符值時(shí) |
class Celsius:
def __get__(self, instance, owner):
return instance._celsius
def __set__(self, instance, value):
if value < -273.15:
raise ValueError("溫度不能低于絕對(duì)零度")
instance._celsius = value
class Temperature:
celsius = Celsius() # 描述符
def __init__(self, celsius):
self.celsius = celsius # 通過(guò)描述符賦值
temp = Temperature(25)
print(temp.celsius) # 25
temp.celsius = 30 # 通過(guò)描述符修改
# temp.celsius = -300 # 報(bào)錯(cuò)
3. 數(shù)值類(lèi)型轉(zhuǎn)換
| 方法 | 調(diào)用時(shí)機(jī) |
|---|---|
| __int__ | int(obj) |
| __float__ | float(obj) |
| __bool__ | bool(obj) |
| __complex__ | complex(obj) |
class Percentage:
def __init__(self, value):
self.value = value
def __int__(self):
return int(self.value)
def __float__(self):
return float(self.value / 100)
def __bool__(self):
return self.value != 0
def __str__(self):
return f"{self.value}%"
p = Percentage(75)
print(int(p)) # 75
print(float(p)) # 0.75
print(bool(p)) # True
print(bool(Percentage(0))) # False
四、魔術(shù)方法最佳實(shí)踐
謹(jǐn)慎使用:只在確實(shí)需要時(shí)實(shí)現(xiàn)魔術(shù)方法
保持一致性:
- 實(shí)現(xiàn)
__eq__時(shí)也應(yīng)實(shí)現(xiàn)__hash__ - 實(shí)現(xiàn)比較運(yùn)算符時(shí)最好實(shí)現(xiàn)全套
性能考慮:魔術(shù)方法會(huì)被頻繁調(diào)用,應(yīng)保持高效
文檔說(shuō)明:明確記錄每個(gè)魔術(shù)方法的行為
避免過(guò)度使用:不是所有類(lèi)都需要成為"全能選手"
五、綜合案例:自定義分?jǐn)?shù)類(lèi)
class Fraction:
"""自定義分?jǐn)?shù)類(lèi),演示多種魔術(shù)方法"""
def __init__(self, numerator, denominator=1):
if denominator == 0:
raise ValueError("分母不能為零")
# 約分
common = self.gcd(numerator, denominator)
self.num = numerator // common
self.den = denominator // common
@staticmethod
def gcd(a, b):
"""計(jì)算最大公約數(shù)"""
while b:
a, b = b, a % b
return a
def __add__(self, other):
"""重載+運(yùn)算符"""
if isinstance(other, int):
other = Fraction(other)
new_num = self.num * other.den + other.num * self.den
new_den = self.den * other.den
return Fraction(new_num, new_den)
__radd__ = __add__ # 反向加法
def __sub__(self, other):
"""重載-運(yùn)算符"""
return self.__add__(-other)
def __neg__(self):
"""重載負(fù)號(hào)"""
return Fraction(-self.num, self.den)
def __mul__(self, other):
"""重載*運(yùn)算符"""
if isinstance(other, int):
other = Fraction(other)
return Fraction(self.num * other.num, self.den * other.den)
__rmul__ = __mul__ # 反向乘法
def __truediv__(self, other):
"""重載/運(yùn)算符"""
if isinstance(other, int):
other = Fraction(other)
return Fraction(self.num * other.den, self.den * other.num)
def __eq__(self, other):
"""重載==運(yùn)算符"""
if isinstance(other, int):
other = Fraction(other)
return self.num == other.num and self.den == other.den
def __lt__(self, other):
"""重載<運(yùn)算符"""
return self.num * other.den < other.num * self.den
def __le__(self, other):
"""重載<=運(yùn)算符"""
return self.__lt__(other) or self.__eq__(other)
def __str__(self):
"""字符串表示"""
if self.den == 1:
return str(self.num)
return f"{self.num}/{self.den}"
def __repr__(self):
"""解釋器表示"""
return f"Fraction({self.num}, {self.den})"
def __float__(self):
"""轉(zhuǎn)換為浮點(diǎn)數(shù)"""
return self.num / self.den
# 使用示例
f1 = Fraction(3, 4)
f2 = Fraction(2, 5)
print(f1 + f2) # 23/20
print(f1 - f2) # 7/20
print(f1 * f2) # 3/10
print(f1 / f2) # 15/8
print(f1 == Fraction(6, 8)) # True
print(f1 < f2) # False
print(float(f1)) # 0.75
print(2 + f1) # 11/4 (調(diào)用__radd__)
通過(guò)這個(gè)完整的分?jǐn)?shù)類(lèi)實(shí)現(xiàn),我們綜合運(yùn)用了多種魔術(shù)方法,使自定義類(lèi)能夠像內(nèi)置類(lèi)型一樣自然地參與各種運(yùn)算和操作。
魔術(shù)方法是Python強(qiáng)大而靈活的特性,合理使用它們可以讓你的類(lèi)更加Pythonic,與Python語(yǔ)言的其他特性無(wú)縫集成。記住,能力越大責(zé)任越大,魔術(shù)方法應(yīng)該用來(lái)增強(qiáng)代碼的清晰度和可用性,而不是制造"魔法"般的復(fù)雜性。
以上就是從入門(mén)到精通的Python魔術(shù)方法(Magic Methods)完全指南的詳細(xì)內(nèi)容,更多關(guān)于Python魔術(shù)方法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python實(shí)現(xiàn)自動(dòng)整理文件的腳本
這篇文章主要介紹了Python實(shí)現(xiàn)自動(dòng)整理文件的腳本,幫助大家更好的利用python處理文件,感興趣的朋友可以了解下2020-12-12
在Python中,不用while和for循環(huán)遍歷列表的實(shí)例
今天小編就為大家分享一篇在Python中,不用while和for循環(huán)遍歷列表的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-02-02
Pytorch之上/下采樣函數(shù)torch.nn.functional.interpolate插值詳解
這篇文章主要介紹了Pytorch之上/下采樣函數(shù)torch.nn.functional.interpolate插值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-04-04
Windows平臺(tái)Python編程必會(huì)模塊之pywin32介紹
在Windows平臺(tái)上,從原來(lái)使用C/C++編寫(xiě)原生EXE程序,到使用Python編寫(xiě)一些常用腳本程序,成熟的模塊的使用使得編程效率大大提高了2019-10-10
使用Python對(duì)SQLite數(shù)據(jù)庫(kù)操作
本文主要介紹了Python對(duì)SQLite數(shù)據(jù)庫(kù)操作的簡(jiǎn)單教程。SQLite是一種嵌入式數(shù)據(jù)庫(kù),它的數(shù)據(jù)庫(kù)就是一個(gè)文件。由于SQLite本身是C寫(xiě)的,而且體積很小,所以,經(jīng)常被集成到各種應(yīng)用程序中,甚至在IOS和Android的APP中都可以集成。2017-04-04
django基于cors解決跨域請(qǐng)求問(wèn)題詳解
這篇文章主要介紹了django基于cors解決跨域請(qǐng)求問(wèn)題詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08
Python pytest 框架通關(guān)指南:自動(dòng)化測(cè)試不再難
文章介紹了pytest一個(gè)高效的Python測(cè)試框架,其優(yōu)點(diǎn)包括簡(jiǎn)單易用、強(qiáng)大的斷言庫(kù)、支持參數(shù)化測(cè)試和豐富的插件生態(tài)系統(tǒng),解釋了安裝、用例運(yùn)行規(guī)則、命令參數(shù)、配置文件、前后置操作、斷言以及參數(shù)化等內(nèi)容,通過(guò)示例代碼展示了其用法和優(yōu)勢(shì),感興趣的朋友跟隨小編一起看看吧2026-03-03

