Python中的魔術(shù)方法功能說明和典型示例
前言
在 Python 中,魔術(shù)方法(Magic Methods) 是一組以雙下劃線 __ 開頭和結(jié)尾的特殊方法(如 __init__、__str__),用于實(shí)現(xiàn)類的核心行為(如構(gòu)造、運(yùn)算、比較、屬性訪問等)。它們由 Python 解釋器自動(dòng)調(diào)用,無(wú)需開發(fā)者顯式觸發(fā),是實(shí)現(xiàn)面向?qū)ο蟾呒?jí)特性(如迭代器、上下文管理器、運(yùn)算符重載)的核心工具。
以下是 Python 中全部核心魔術(shù)方法的分類整理,涵蓋初始化、屬性訪問、運(yùn)算重載、容器行為、迭代器、上下文管理等場(chǎng)景,并附帶功能說明和典型示例,幫助你系統(tǒng)理解其用法。
一、初始化與銷毀:對(duì)象的創(chuàng)建與回收
這類方法控制對(duì)象的創(chuàng)建、初始化和銷毀過程,是類最基礎(chǔ)的魔術(shù)方法。
| 魔術(shù)方法 | 功能說明 | 示例代碼 |
|---|---|---|
__new__(cls, *args, **kwargs) | 創(chuàng)建對(duì)象:在 __init__ 之前調(diào)用,返回類的實(shí)例(負(fù)責(zé)內(nèi)存分配),常用于不可變類型(如 int、str)的定制。 | python class Singleton: _instance = None def __new__(cls): if not cls._instance: cls._instance = super().__new__(cls) return cls._instance s1 = Singleton() s2 = Singleton() print(s1 is s2) # True(單例模式) |
__init__(self, *args, **kwargs) | 初始化對(duì)象:對(duì)象創(chuàng)建后調(diào)用,用于初始化實(shí)例屬性(無(wú)返回值),是最常用的魔術(shù)方法。 | python class Person: def __init__(self, name, age): self.name = name self.age = age p = Person("Alice", 25) print(p.name) # Alice |
__del__(self) | 銷毀對(duì)象:對(duì)象被垃圾回收時(shí)調(diào)用(時(shí)機(jī)不確定,不建議依賴),用于釋放資源(如文件句柄)。 | python class FileHandler: def __init__(self, path): self.file = open(path, "w") def __del__(self): self.file.close() # 回收時(shí)關(guān)閉文件 |
二、屬性訪問:控制實(shí)例屬性的讀寫
這類方法用于定制實(shí)例屬性的訪問、賦值、刪除邏輯,實(shí)現(xiàn)屬性的封裝、校驗(yàn)或動(dòng)態(tài)計(jì)算(如@property 的底層原理)。
| 魔術(shù)方法 | 功能說明 | 示例代碼 |
|---|---|---|
__getattr__(self, name) | 當(dāng)訪問不存在的實(shí)例屬性時(shí)調(diào)用,返回屬性值或拋出 AttributeError。 | python class DynamicAttr: def __getattr__(self, name): if name == "full_name": return f"{self.first_name} {self.last_name}" raise AttributeError(f"No attribute {name}") d = DynamicAttr() d.first_name = "Bob" d.last_name = "Smith" print(d.full_name) # Bob Smith |
__setattr__(self, name, value) | 當(dāng)給實(shí)例屬性賦值時(shí)調(diào)用(包括存在和不存在的屬性),可用于屬性校驗(yàn)。 | python class Person: def __setattr__(self, name, value): if name == "age" and (not isinstance(value, int) or value < 0): raise ValueError("Age must be a non-negative integer") super().__setattr__(name, value) # 必須調(diào)用父類方法,避免遞歸 p = Person() p.age = 25 # 正常 p.age = -5 # 拋出 ValueError |
__delattr__(self, name) | 當(dāng)刪除實(shí)例屬性(del obj.name)時(shí)調(diào)用,可用于限制屬性刪除。 | python class ProtectedAttr: def __delattr__(self, name): if name == "id": raise PermissionError("Cannot delete 'id' attribute") super().__delattr__(name) p = ProtectedAttr() p.id = 123 del p.id # 拋出 PermissionError |
__getattribute__(self, name) | 訪問任何實(shí)例屬性時(shí)都會(huì)優(yōu)先調(diào)用(包括存在的屬性),需謹(jǐn)慎使用(避免遞歸),常用于全局屬性控制。 | python class LogAttr: def __getattribute__(self, name): print(f"Accessing attribute: {name}") return super().__getattribute__(name) # 必須調(diào)用父類,避免遞歸 l = LogAttr() l.x = 10 print(l.x) # 先打印 "Accessing attribute: x",再輸出 10 |
三、字符串表示:定制對(duì)象的打印與轉(zhuǎn)換
這類方法控制對(duì)象在字符串場(chǎng)景下的表現(xiàn)(如 print(obj)、str(obj)、repr(obj)),幫助調(diào)試和用戶友好展示。
| 魔術(shù)方法 | 功能說明 | 示例代碼 |
|---|---|---|
__str__(self) | 當(dāng)調(diào)用 str(obj) 或 print(obj) 時(shí)調(diào)用,返回用戶友好的字符串(可讀性優(yōu)先)。 | python class Person: def __init__(self, name): self.name = name def __str__(self): return f"Person(name='{self.name}')" p = Person("Alice") print(p) # 輸出 Person(name='Alice') |
__repr__(self) | 當(dāng)調(diào)用 repr(obj) 或在交互式環(huán)境中直接輸入對(duì)象時(shí)調(diào)用,返回開發(fā)者友好的字符串(用于還原對(duì)象,唯一性優(yōu)先)。 | python class Person: def __init__(self, name): self.name = name def __repr__(self): return f"Person('{self.name}')" p = Person("Bob") print(repr(p)) # 輸出 Person('Bob') (可直接用于創(chuàng)建對(duì)象) |
__format__(self, format_spec) | 當(dāng)調(diào)用 format(obj, format_spec) 或使用 f-string 格式化時(shí)調(diào)用,定制格式化邏輯。 | python class Time: def __init__(self, h, m): self.h = h self.m = m def __format__(self, spec): if spec == "24h": return f"{self.h:02d}:{self.m:02d}" elif spec == "12h": period = "AM" if self.h < 12 else "PM" return f"{self.h%12:02d}:{self.m:02d} {period}" t = Time(15, 30) print(f"24h: {t:24h}") # 24h: 15:30 print(f"12h: {t:12h}") # 12h: 03:30 PM |
__bytes__(self) | 當(dāng)調(diào)用 bytes(obj) 時(shí)調(diào)用,返回對(duì)象的字節(jié)表示(bytes 類型)。 | python class Text: def __init__(self, content): self.content = content def __bytes__(self): return self.content.encode("utf-8") t = Text("Hello") print(bytes(t)) # b'Hello' |
四、運(yùn)算符重載:讓對(duì)象支持算術(shù)/比較運(yùn)算
這類方法允許自定義類的實(shí)例支持 Python 內(nèi)置運(yùn)算符(如 +、>、==),是實(shí)現(xiàn)“對(duì)象運(yùn)算”的核心。
4.1 算術(shù)運(yùn)算符(+、-、*、/ 等)
| 魔術(shù)方法 | 對(duì)應(yīng)運(yùn)算符 | 功能說明 | 示例(以 __add__ 為例) |
|---|---|---|---|
__add__(self, other) | + | 加法(self + other) | python class Vector: def __init__(self, x): self.x = x def __add__(self, other): return Vector(self.x + other.x) v1 = Vector(2) v2 = Vector(3) print((v1 + v2).x) # 5 |
__sub__(self, other) | - | 減法(self - other) | - |
__mul__(self, other) | * | 乘法(self * other) | - |
__truediv__(self, other) | / | 真除法(self / other) | - |
__floordiv__(self, other) | // | 地板除法(self // other) | - |
__mod__(self, other) | % | 取模(self % other) | - |
__pow__(self, other) | ** | 冪運(yùn)算(self ** other) | - |
注:反向算術(shù)運(yùn)算符(如
other + self,當(dāng)other不支持與self運(yùn)算時(shí)調(diào)用):__radd__、__rsub__、__rmul__等,用法與正向類似。
4.2 比較運(yùn)算符(==、>、< 等)
| 魔術(shù)方法 | 對(duì)應(yīng)運(yùn)算符 | 功能說明 | 示例(以 __eq__ 和 __gt__ 為例) |
|---|---|---|---|
__eq__(self, other) | == | 等于(self == other) | python class Person: def __init__(self, id): self.id = id def __eq__(self, other): return self.id == other.id p1 = Person(1) p2 = Person(1) print(p1 == p2) # True |
__ne__(self, other) | != | 不等于(self != other) | (若未定義,默認(rèn)返回 not __eq__ 的結(jié)果) |
__gt__(self, other) | > | 大于(self > other) | python class Number: def __init__(self, n): self.n = n def __gt__(self, other): return self.n > other.n num1 = Number(5) num2 = Number(3) print(num1 > num2) # True |
__ge__(self, other) | >= | 大于等于 | - |
__lt__(self, other) | < | 小于 | - |
__le__(self, other) | <= | 小于等于 | - |
4.3 賦值運(yùn)算符(+=、-=、*= 等)
| 魔術(shù)方法 | 對(duì)應(yīng)運(yùn)算符 | 功能說明 | 示例(以 __iadd__ 為例) |
|---|---|---|---|
__iadd__(self, other) | += | 增量加法(self += other) | python class Counter: def __init__(self, num): self.num = num def __iadd__(self, other): self.num += other return self c = Counter(10) c += 5 print(c.num) # 15 |
__isub__(self, other) | -= | 增量減法 | - |
__imul__(self, other) | *= | 增量乘法 | - |
__itruediv__(self, other) | /= | 增量真除法 | - |
4.4 位運(yùn)算符(&、|、^、<<、>> 等)
| 魔術(shù)方法 | 對(duì)應(yīng)運(yùn)算符 | 功能說明 |
|---|---|---|
__and__(self, other) | & | 按位與 |
__or__(self, other) | ` | ` |
__xor__(self, other) | ^ | 按位異或 |
__lshift__(self, other) | << | 左移 |
__rshift__(self, other) | >> | 右移 |
五、容器行為:讓對(duì)象像列表/字典一樣工作
這類方法允許自定義類的實(shí)例支持容器操作(如 len(obj)、obj[key]、for item in obj),實(shí)現(xiàn)類似列表、字典的行為。
| 魔術(shù)方法 | 對(duì)應(yīng)操作 | 功能說明 | 示例(實(shí)現(xiàn)一個(gè)簡(jiǎn)單列表) |
|---|---|---|---|
__len__(self) | len(obj) | 返回容器的元素個(gè)數(shù)(必須返回整數(shù))。 | python class MyList: def __init__(self, data): self.data = data def __len__(self): return len(self.data) ml = MyList([1,2,3]) print(len(ml)) # 3 |
__getitem__(self, key) | obj[key] | 獲取容器中 key 對(duì)應(yīng)的元素(支持索引、切片),無(wú)對(duì)應(yīng) key 時(shí)拋 KeyError。 | python class MyList: def __init__(self, data): self.data = data def __getitem__(self, key): return self.data[key] ml = MyList([1,2,3]) print(ml[1]) # 2 print(ml[1:]) # [2,3] |
__setitem__(self, key, value) | obj[key] = value | 給容器中 key 對(duì)應(yīng)的元素賦值,無(wú)對(duì)應(yīng) key 時(shí)可新增。 | python class MyList: def __init__(self, data): self.data = data def __setitem__(self, key, value): self.data[key] = value ml = MyList([1,2,3]) ml[1] = 10 print(ml.data) # [1,10,3] |
__delitem__(self, key) | del obj[key] | 刪除容器中 key 對(duì)應(yīng)的元素,無(wú)對(duì)應(yīng) key 時(shí)拋 KeyError。 | python class MyList: def __init__(self, data): self.data = data def __delitem__(self, key): del self.data[key] ml = MyList([1,2,3]) del ml[1] print(ml.data) # [1,3] |
__contains__(self, item) | item in obj / item not in obj | 判斷 item 是否在容器中,返回布爾值(未定義則默認(rèn)遍歷判斷)。 | python class MyList: def __init__(self, data): self.data = data def __contains__(self, item): return item in self.data ml = MyList([1,2,3]) print(2 in ml) # True print(4 in ml) # False |
__iter__(self) | for item in obj | 返回一個(gè)迭代器(用于遍歷容器),通常與 yield 配合或返回 iter(self.data)。 | python class MyList: def __init__(self, data): self.data = data def __iter__(self): for item in self.data: yield item # 生成迭代器 ml = MyList([1,2,3]) for num in ml: print(num) # 1, 2, 3 |
__reversed__(self) | reversed(obj) | 返回容器的反向迭代器(用于 reversed(obj))。 | python class MyList: def __init__(self, data): self.data = data def __reversed__(self): return reversed(self.data) ml = MyList([1,2,3]) print(list(reversed(ml))) # [3,2,1] |
六、迭代器與生成器:控制迭代過程
迭代器的核心是 __iter__ 和 __next__ 方法,生成器則是通過 yield 簡(jiǎn)化迭代器實(shí)現(xiàn),但魔術(shù)方法仍可定制生成器行為。
| 魔術(shù)方法 | 功能說明 | 示例(實(shí)現(xiàn)一個(gè)自定義迭代器) |
|---|---|---|
__iter__(self) | 返回迭代器對(duì)象本身(必須實(shí)現(xiàn),用于 for 循環(huán))。 | python class Counter: def __init__(self, max_num): self.max = max_num self.current = 0 def __iter__(self): return self # 返回自身作為迭代器 def __next__(self): if self.current < self.max: self.current += 1 return self.current else: raise StopIteration # 迭代結(jié)束 c = Counter(3) for num in c: print(num) # 1, 2, 3 |
__next__(self) | 返回下一個(gè)迭代元素,無(wú)元素時(shí)拋 StopIteration(迭代器核心)。 | - |
__send__(self, value) | 向生成器發(fā)送值(用于 yield 表達(dá)式接收外部值),生成器專用。 | python def generator(): while True: x = yield # 接收外部發(fā)送的值 print(f"Received: {x}") g = generator() next(g) # 啟動(dòng)生成器 g.send(10) # 輸出 "Received: 10" g.send(20) # 輸出 "Received: 20" |
__close__(self) | 關(guān)閉生成器(調(diào)用后生成器無(wú)法再生成值,拋 GeneratorExit)。 | python def generator(): yield 1 yield 2 g = generator() print(next(g)) # 1 g.close() next(g) # 拋 StopIteration |
七、上下文管理:實(shí)現(xiàn)with語(yǔ)句支持
通過 __enter__ 和 __exit__ 方法,讓對(duì)象支持 with 語(yǔ)句(自動(dòng)管理資源,如文件關(guān)閉、鎖釋放)。
| 魔術(shù)方法 | 功能說明 | 示例(實(shí)現(xiàn)一個(gè)自定義文件管理器) |
|---|---|---|
__enter__(self) | 進(jìn)入 with 塊時(shí)調(diào)用,返回的對(duì)象可賦值給 as 后的變量(如 with open(...) as f)。 | python class MyFile: def __init__(self, path, mode): self.path = path self.mode = mode def __enter__(self): self.file = open(self.path, self.mode) return self.file # 賦值給 as 后的變量 def __exit__(self, exc_type, exc_val, exc_tb): self.file.close() # 退出 with 塊時(shí)自動(dòng)關(guān)閉 # 使用 with MyFile("test.txt", "w") as f: f.write("Hello") # 文件已自動(dòng)關(guān)閉 |
__exit__(self, exc_type, exc_val, exc_tb) | 退出 with 塊時(shí)調(diào)用,處理異常(若有):- exc_type:異常類型(無(wú)異常則為 None)- exc_val:異常實(shí)例- exc_tb:異常追蹤棧返回 True 表示異常已處理,不向外傳播。 | python class SafeFile: def __init__(self, path): self.path = path def __enter__(self): self.file = open(self.path, "w") return self.file def __exit__(self, exc_type, exc_val, exc_tb): self.file.close() if exc_type is not None: print(f"Error: {exc_val}") return True # 處理異常,不向外傳播 # 測(cè)試異常 with SafeFile("test.txt") as f: f.write(123) # 拋出 TypeError # 輸出 "Error: write() argument must be str, not int",無(wú)崩潰 |
八、其他常用魔術(shù)方法
8.1 可調(diào)用對(duì)象:讓實(shí)例像函數(shù)一樣調(diào)用
通過 __call__ 方法,讓類的實(shí)例支持函數(shù)調(diào)用語(yǔ)法(obj())。
| 魔術(shù)方法 | 功能說明 | 示例代碼 |
|---|---|---|
__call__(self, *args, **kwargs) | 實(shí)例被調(diào)用時(shí)執(zhí)行(obj(*args)),可實(shí)現(xiàn)“函數(shù)對(duì)象”或“狀態(tài)保持的函數(shù)”。 | python class Adder: def __init__(self, base): self.base = base def __call__(self, x): return self.base + x add5 = Adder(5) print(add5(3)) # 8(等價(jià)于 Adder(5)(3)) |
8.2 哈希與可哈希性
__hash__ 用于計(jì)算對(duì)象的哈希值(支持作為字典鍵、集合元素),__eq__ 與 __hash__ 需滿足:若 a == b,則 hash(a) == hash(b)。
| 魔術(shù)方法 | 功能說明 | 示例代碼 |
|---|---|---|
__hash__(self) | 返回對(duì)象的哈希值(整數(shù)),未定義則默認(rèn)基于內(nèi)存地址。 | python class Point: def __init__(self, x, y): self.x = x self.y = y def __eq__(self, other): return (self.x, self.y) == (other.x, other.y) def __hash__(self): return hash((self.x, self.y)) # 基于屬性哈希 p1 = Point(1,2) p2 = Point(1,2) print(hash(p1) == hash(p2)) # True d = {p1: "A"} print(d[p2]) # A(可作為字典鍵) |
8.3 類型轉(zhuǎn)換
這類方法用于將對(duì)象轉(zhuǎn)換為其他內(nèi)置類型(如 int(obj)、bool(obj))。
| 魔術(shù)方法 | 對(duì)應(yīng)函數(shù) | 功能說明 | 示例代碼 |
|---|---|---|---|
__int__(self) | int(obj) | 轉(zhuǎn)換為整數(shù) | python class Number: def __init__(self, n): self.n = n def __int__(self): return int(self.n) num = Number(3.8) print(int(num)) # 3 |
__float__(self) | float(obj) | 轉(zhuǎn)換為浮點(diǎn)數(shù) | - |
__bool__(self) | bool(obj) | 轉(zhuǎn)換為布爾值(if obj 時(shí)調(diào)用),未定義則默認(rèn):空容器/0 為 False,否則 True。 | python class EmptyCheck: def __init__(self, data): self.data = data def __bool__(self): return len(self.data) > 0 ec = EmptyCheck([]) print(bool(ec)) # False ec2 = EmptyCheck([1]) print(bool(ec2)) # True |
總結(jié)
魔術(shù)方法是 Python 面向?qū)ο蟮?ldquo;靈魂”,其核心價(jià)值在于:
- 統(tǒng)一接口:讓自定義類的行為與內(nèi)置類型(如列表、字典)保持一致(如
len(obj)、for item in obj); - 靈活定制:通過重載運(yùn)算符、屬性訪問、迭代邏輯等,實(shí)現(xiàn)高度定制化的類(如單例、自定義容器、上下文管理器);
- 隱式調(diào)用:無(wú)需顯式調(diào)用,由 Python 解釋器自動(dòng)觸發(fā),簡(jiǎn)化代碼。
實(shí)際開發(fā)中,無(wú)需記憶所有魔術(shù)方法,而是根據(jù)需求選擇(如實(shí)現(xiàn) with 用 __enter__/__exit__,實(shí)現(xiàn)迭代用 __iter__/__next__),并遵循“最小必要”原則——僅實(shí)現(xiàn)需要的魔術(shù)方法,避免過度復(fù)雜。
到此這篇關(guān)于Python中魔術(shù)方法功能的文章就介紹到這了,更多相關(guān)Python魔術(shù)方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Pandas出現(xiàn)KeyError的問題解決及分析
本文主要介紹了Pandas出現(xiàn)KeyError的問題解決及分析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01
Pycharm編輯器功能之代碼折疊效果的實(shí)現(xiàn)代碼
這篇文章主要介紹了Pycharm編輯器功能之代碼折疊效果的實(shí)現(xiàn)代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10
python實(shí)現(xiàn)mean-shift聚類算法
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)mean-shift聚類算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06
SymPy庫(kù)關(guān)于矩陣的基本操作和運(yùn)算
本文主要介紹了SymPy庫(kù)關(guān)于矩陣的基本操作和運(yùn)算,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03

