在 Python 中,函數(shù)(function)與方法(method)是兩種密切相關(guān)但又有所區(qū)別的對(duì)象。
“方法對(duì)象”并非一種獨(dú)立的新類型,而是函數(shù)對(duì)象通過(guò)機(jī)制在類或?qū)嵗媳辉L問時(shí),動(dòng)態(tài)生成的包裝對(duì)象。
要理解方法對(duì)象的內(nèi)部結(jié)構(gòu),關(guān)鍵在于認(rèn)識(shí)其兩個(gè)核心屬性:
__func__:指向方法背后的原始函數(shù)對(duì)象。
__self__:指向方法所綁定的對(duì)象(實(shí)例或類)。
其中 __func__ 是方法對(duì)象最核心的組成部分,它決定了方法的最終執(zhí)行邏輯。
一、方法對(duì)象與函數(shù)對(duì)象的區(qū)分
在類體內(nèi)的使用 def 語(yǔ)句定義函數(shù),在創(chuàng)建時(shí)是一個(gè)函數(shù)對(duì)象,并存放在類的命名空間(類.__dict__)中:
print(type(a.f)) # -> 方法對(duì)象? A.f 直接從類命名空間獲取,是一個(gè)函數(shù)對(duì)象。
? a.f 通過(guò)描述符協(xié)議觸發(fā)函數(shù)對(duì)象的 __get__ 方法,返回一個(gè)綁定方法對(duì)象。
關(guān)鍵區(qū)別:__func__ 是方法對(duì)象的專屬屬性:
hasattr(a.f, "__func__") # True,方法對(duì)象有 __func__二、__func__ 的定義與語(yǔ)義
對(duì)于方法對(duì)象,method.__func__ 始終指向定義在類中、存放于類命名空間(類.__dict__)里的那個(gè)原始函數(shù)對(duì)象。
(1)方法對(duì)象的結(jié)構(gòu)
當(dāng)通過(guò)實(shí)例訪問方法(如 a.f)時(shí),Python 內(nèi)部執(zhí)行以下流程:
1、在類 A 的命名空間中找到函數(shù)對(duì)象 A.__dict__['f']。
2、調(diào)用該函數(shù)對(duì)象的 __get__ 方法(描述符協(xié)議)。
3、生成一個(gè)綁定方法對(duì)象,其內(nèi)部由兩部分構(gòu)成:
? method.__func__:指向原始函數(shù)對(duì)象。
? method.__self__:指向被綁定的實(shí)例 a。
m.__self__ is a # True,綁定到實(shí)例 a__func__ 永遠(yuǎn)指向類命名空間中的原始函數(shù),不會(huì)指向方法對(duì)象本身,也不會(huì)因?qū)嵗煌兓?/p>
(2)方法調(diào)用的展開
一個(gè)典型的方法調(diào)用 a.f(x),其內(nèi)部等價(jià)于:
a.f.__func__(a.f.__self__, x) # 即:用綁定的實(shí)例作為第一參數(shù)調(diào)用原始函數(shù)因此:
? method.__func__ 決定了執(zhí)行哪個(gè)函數(shù)。
? method.__self__ 決定了自動(dòng)作為第一個(gè)參數(shù)傳入的對(duì)象。
三、__func__ 的常見應(yīng)用場(chǎng)景
(1)判斷兩個(gè)方法是否基于同一函數(shù)
a1.f.__func__ is a2.f.__func__ # True盡管綁定到不同的實(shí)例,但它們背后的函數(shù)對(duì)象是同一個(gè)。
(2)訪問函數(shù)元數(shù)據(jù)
方法對(duì)象本身不存儲(chǔ) __name__、__doc__ 等元數(shù)據(jù),這些信息都存儲(chǔ)在 __func__ 中。
print(a.f.__doc__) # 實(shí)際上訪問的是 a.f.__func__.__doc__(3)繞過(guò)綁定機(jī)制,直接調(diào)用底層函數(shù)
在某些高級(jí)場(chǎng)景(如反射、調(diào)試或框架設(shè)計(jì))中,可能需要直接操作原始函數(shù)。
a.f.__func__(a, 10) # 通過(guò)方法的 __func__ 調(diào)用(4)分析裝飾器的影響
裝飾器通常會(huì)替換類中的原始函數(shù)。此時(shí) __func__ 指向的是裝飾器返回的包裝函數(shù)(wrapper)。
# 使用 functools.wraps 裝飾器可以保留原始函數(shù)的元數(shù)據(jù)。四、類方法與靜態(tài)方法中的 __func__
__func__ 屬性也存在于類方法(@classmethod)和靜態(tài)方法(@staticmethod)對(duì)象中,但其 __self__ 的綁定對(duì)象有所不同。
? 實(shí)例方法:__self__ 綁定到實(shí)例。
? 類方法:__self__ 綁定到類本身。
? 靜態(tài)方法:靜態(tài)方法訪問后返回普通函數(shù)對(duì)象,因此不具有 __func__ 或 __self__。
print(MyClass.static_method.__self__) # AttributeError: 'function' object has no attribute '__self__'五、常見誤解與澄清
誤解 1:所有函數(shù)都有 __func__ 屬性。
正解:只有方法對(duì)象(包括實(shí)例方法、類方法)才擁有 __func__ 屬性。普通函數(shù)沒有。
誤解 2:每個(gè)方法對(duì)象都包含一個(gè)獨(dú)立的函數(shù)副本。
正解:所有同源的方法對(duì)象共享同一個(gè) __func__ 對(duì)象,沒有復(fù)制行為。
誤解 3:通過(guò)類訪問屬性得到的就是方法。
正解:通過(guò)類訪問得到的是函數(shù)對(duì)象,通過(guò)實(shí)例訪問才會(huì)觸發(fā)綁定,生成方法對(duì)象。
誤解 4:__func__ 和 __self__ 是用戶可以隨意修改的。
正解:它們是只讀屬性,由 Python 在創(chuàng)建方法對(duì)象時(shí)自動(dòng)設(shè)置,旨在保證方法綁定機(jī)制的正確性。
小結(jié)
__func__ 是 Python 方法對(duì)象的核心屬性,它指向方法所依賴的原始函數(shù)對(duì)象。綁定方法對(duì)象(包括實(shí)例方法與類方法)由 __func__ 與 __self__ 組合而成:__func__ 提供執(zhí)行邏輯,__self__ 提供綁定的對(duì)象。因此 a.f(x) 等價(jià)于 a.f.__func__(a, x)。只有方法對(duì)象(而非函數(shù)對(duì)象)才具有 __func__。這一屬性用于反射、調(diào)試、框架內(nèi)部行為分析,如比較兩個(gè)方法是否來(lái)自同一函數(shù)、訪問函數(shù)元數(shù)據(jù)、或繞過(guò)綁定機(jī)制直接調(diào)用函數(shù)。
理解 __func__ 有助于深入掌握 Python 的方法綁定模型與描述符機(jī)制。
![]()
“點(diǎn)贊有美意,贊賞是鼓勵(lì)”
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.