
作者:豌豆花下貓
來(lái)源:Python貓
花下貓語(yǔ):前兩天,我偶然在一個(gè)知識(shí)星球(劉欣老師的“碼農(nóng)翻身”)里看到一篇主題,劉老師表示 python 的類(lèi)方法非要帶個(gè) self,而不像其它語(yǔ)言那樣隱藏起來(lái),這讓人很不爽。我對(duì)此也有同感。在經(jīng)過(guò)群聊討論后,我獲知 Guido 曾經(jīng)專(zhuān)門(mén)撰文解釋過(guò)這個(gè)問(wèn)題。這篇文章并不好懂,我抽空先翻譯出來(lái)了,看看能收到什么回應(yīng)。如果可能的話(huà),后續(xù)再另寫(xiě)文章分析。
布魯斯·??藸枺˙ruce Eckel)發(fā)了篇博文[1],提議從類(lèi)方法的形參列表中刪除“self”。我將解釋為什么這個(gè)提議不能通過(guò)。(譯注:Bruce 是《Thinking in Java》、《Thinking in C++》等多本書(shū)籍的作者,也是個(gè) Python 開(kāi)發(fā)者。他的文章總結(jié)了當(dāng)年在巴西 Pycon 上的一次討論,主要觀點(diǎn)是在定義類(lèi)方法時(shí),形參中的“self”是多余的,而且由它引發(fā)的報(bào)錯(cuò)信息具有一定的誤導(dǎo)性。)
Bruce 的提議
Bruce 知道,我們需要一種方法來(lái)區(qū)分對(duì)實(shí)例變量的引用和對(duì)其它變量的引用,因此他建議將“self”設(shè)為關(guān)鍵字。
考慮一種典型的類(lèi),它有一個(gè)方法,例如:
class C: def meth(self, arg): self.val = arg return self.val
跟據(jù)Bruce 的提議,這將變?yōu)椋?
class C: def meth(arg): # Look ma, no self! self.val = arg return self.val
這樣每個(gè)方法會(huì)節(jié)省 6 個(gè)字符。但我不覺(jué)得 Bruce 提出這個(gè)建議是為了減少打字。
我認(rèn)為他真正關(guān)心的是程序員(可能來(lái)自其它語(yǔ)言)所浪費(fèi)的時(shí)間,有時(shí)候似乎不需要指定“self”參數(shù),而且他們偶爾忘記了要加(即使他們十分清楚——習(xí)慣是一種強(qiáng)大的力量)。確實(shí),與忘記在實(shí)例變量或方法引用之前鍵入“self.”相比,從參數(shù)列表中省略“self”,往往會(huì)導(dǎo)致很模糊的錯(cuò)誤消息。
也許更糟糕的是(如 Bruce 所述),當(dāng)正確地聲明了方法,但是在調(diào)用時(shí)的參數(shù)數(shù)量不對(duì),這時(shí)收到的錯(cuò)誤消息。如 Bruce 給出的以下示例:
Traceback (most recent call last): File "classes.py", line 9, in obj.m2(1) TypeError: m2() takes exactly 3 arguments (2 given)
我贊同它是令人困惑的,但是我寧愿去解決此錯(cuò)誤消息,而不是修改語(yǔ)言。
為什么 Bruce 的提議不可行
首先,讓我提出一些與 Bruce 的提議相反的典型論點(diǎn)。
這有一個(gè)很好的論據(jù)可以證明,在參數(shù)列表中使用顯式的“self”,可以增強(qiáng)以下兩種調(diào)用方法在理論上的等效性。假設(shè)“ foo”是“C”的一個(gè)實(shí)例:
foo.meth(arg) == C.meth(foo, arg)
(譯注:說(shuō)實(shí)話(huà),我沒(méi)有理解這個(gè)例子的意思。以下僅是個(gè)人看法。在類(lèi)的內(nèi)部定義方法時(shí),可能會(huì)產(chǎn)生幾種不同的方法:實(shí)例方法、類(lèi)方法和 靜態(tài)方法。它們的作用和行為是不同的,那么在定義和調(diào)用時(shí)怎么做區(qū)分呢?Python 約定了一種方式,即在定義時(shí)用第一個(gè)參數(shù)作區(qū)分:self 表示實(shí)例方法、cls或其它符號(hào) 表示類(lèi)方法……三種方法都可以被類(lèi)的實(shí)例調(diào)用,而且看起來(lái)一模一樣,如上例的等號(hào)左側(cè)那樣。這時(shí)候就要靠定義時(shí)賦予的參數(shù)來(lái)區(qū)分了,像上例等號(hào)右側(cè),第一個(gè)參數(shù)是實(shí)例對(duì)象,表明此處是個(gè)實(shí)例方法。)
另一個(gè)論據(jù)是,在參數(shù)列表中使用顯式的“self”,將一個(gè)函數(shù)插入一個(gè)類(lèi),獲得動(dòng)態(tài)地修改一個(gè)類(lèi)的能力,創(chuàng)建出相應(yīng)的一個(gè)類(lèi)方法。
例如,我們可以創(chuàng)建一個(gè)與上面的“C”完全等效的類(lèi),如下所示:
# Define an empty class: class C: pass # Define a global function: def meth(myself, arg): myself.val = arg return myself.val # Poke the method into the class: C.meth = meth
請(qǐng)注意,我將“self”參數(shù)重命名為“myself”,以強(qiáng)調(diào)(在語(yǔ)法上)我們不是在此處定義一個(gè)方法(譯注:類(lèi)外部的是函數(shù),即 function,類(lèi)內(nèi)部的是方法,即 method)。
這樣之后,C 的實(shí)例就具有了一個(gè)“meth”方法,該方法有一個(gè)參數(shù),且功能跟之前的完全一樣。對(duì)于在把方法插入類(lèi)之前就創(chuàng)建的那些 C 的實(shí)例,它甚至也適用。
我想 Bruce 并不特別在意前述的等效性。我同意這只是理論上的重要。我能想到的唯一例外是舊式的調(diào)用超級(jí)方法的習(xí)語(yǔ)(idiom)。但是,這個(gè)習(xí)語(yǔ)很容易出錯(cuò)(正是由于需要顯式地傳遞"self"的原因),這就是為什么在 Python 3000中,我建議在所有情況下都使用"super()"的原因。
Bruce 可能會(huì)想到一種使第二個(gè)等效例子起作用的方法——在某些情況下,這種等效性真的很重要。我不知道 Bruce 花了多少時(shí)間思考如何實(shí)現(xiàn)他的提議,但是我想他正在考慮將一個(gè)名為“self”的額外形參自動(dòng)地添加到直接地在類(lèi)內(nèi)部定義的所有方法的思路(我必須說(shuō)是“直接地”,以便那些嵌套在方法內(nèi)部的函數(shù),能免于這種自動(dòng)操作)。這樣,可以使第一個(gè)等效例子保持等效。
但是,有一種情況我認(rèn)為 Bruce 不能在不向編譯器中添加某種 ESP 的情況下解決:裝飾器。我相信這是 Bruce 的提議的最終敗筆。
當(dāng)裝飾一個(gè)方法時(shí),我們不知道是否要自動(dòng)地給它加一個(gè)“self”參數(shù):裝飾器可以將函數(shù)變成一個(gè)靜態(tài)方法(沒(méi)有“self”)或一個(gè)類(lèi)方法(有一個(gè)有趣的 self,它指向一個(gè)類(lèi)而不是一個(gè)實(shí)例),或者可以做一些完全不同的事情(用純 Python 實(shí)現(xiàn)“ @classmethod”或“ @staticmethod”的裝飾器是繁瑣的)。除非知道裝飾器的用途,否則沒(méi)有其它辦法來(lái)確定是否要賦予正在定義的方法一個(gè)隱式的“self”參數(shù)。
我拒絕諸如特殊包裝的“@classmethod”和“@staticmethod”之類(lèi)的黑科技。我也認(rèn)為除了自檢外,自動(dòng)地確定某個(gè)方法是類(lèi)方法(class method)、實(shí)例方法(instance method)還是靜態(tài)方法(static method),這不是一個(gè)好主意(就像在 Bruce 的文章的評(píng)論中,有人建議的那樣):這使得很難僅僅根據(jù)方法前的“def”,來(lái)決定應(yīng)該怎樣調(diào)用該方法。
(譯注:對(duì)于一個(gè)方法,在當(dāng)前的添加了相應(yīng)參數(shù)的情況下,可以簡(jiǎn)單地加裝飾器,區(qū)分它是哪種方法,調(diào)用時(shí)也容易區(qū)分調(diào)用;但是,如果沒(méi)有加參數(shù),即使可以用神奇的自動(dòng)機(jī)制來(lái)區(qū)分出它是哪種方法,但在調(diào)用時(shí),你不好確定該怎么調(diào)用)。
在評(píng)論中,我看到了一些非常極端的對(duì) Bruce 的提議的附和,但通常的代價(jià)是使得規(guī)則難以遵循,或者要求對(duì)語(yǔ)言進(jìn)行更深層的修改,這令我們極其難以接受它,特別是合入 Python 3.1。順便說(shuō)一句,對(duì)于 3.1,再次聲明我們的規(guī)則,新特性只有在保持向后兼容的情況下才是可接受的。
有一個(gè)似乎可行的建議(可以使它向后兼容)是把類(lèi)中的
def foo(self, arg): ...
改成這樣的語(yǔ)法糖:
def self.foo(arg): ...
但我不認(rèn)同它把“self”變?yōu)楸A糇郑╮eserved word),或者要求前綴必須是“self”。如果這樣做了,那對(duì)于類(lèi)方法,很容易也出現(xiàn)這種情況:
@classmethod def cls.foo(arg): ...
好了,相比于現(xiàn)狀,我并沒(méi)有更喜歡這個(gè)。但是相比于 Bruce 的提議或在他的博客評(píng)論區(qū)中提出的更極端的說(shuō)法,我認(rèn)為這個(gè)要好得多,而且它具有向后兼容的巨大優(yōu)勢(shì),并且不需要很費(fèi)力,就可以寫(xiě)成帶有參考實(shí)現(xiàn)的 PEP。(我想 Bruce 應(yīng)該會(huì)發(fā)現(xiàn)自己提案中的缺陷,如果他真的付出努力嘗試編寫(xiě)可靠的 PEP 或者嘗試實(shí)現(xiàn)它。)
我可以繼續(xù)聊很多,但這是一個(gè)陽(yáng)光明媚的周日早晨,而我還有其它的計(jì)劃... :-)
作者:Guido van Rossum,寫(xiě)于:2008.10.26
參考資料
[1] Bruce博文:http://www.artima.com/weblogs/viewpost.jsp?thread=239003
[2] Guido原文: https://neopythonic.blogspot.com/2008/10/why-explicit-self-has-to-stay.html
——熱門(mén)課程推薦:
想學(xué)習(xí)PYTHON數(shù)據(jù)分析與金融數(shù)字化轉(zhuǎn)型精英訓(xùn)練營(yíng),您可以點(diǎn)擊>>>“人才轉(zhuǎn)型”了解課程詳情;
想從事業(yè)務(wù)型數(shù)據(jù)分析師,您可以點(diǎn)擊>>>“數(shù)據(jù)分析師”了解課程詳情;
想從事大數(shù)據(jù)分析師,您可以點(diǎn)擊>>>“大數(shù)據(jù)就業(yè)”了解課程詳情;
想成為人工智能工程師,您可以點(diǎn)擊>>>“人工智能就業(yè)”了解課程詳情;
想了解Python數(shù)據(jù)分析,您可以點(diǎn)擊>>>“Python數(shù)據(jù)分析師”了解課程詳情;
想咨詢(xún)互聯(lián)網(wǎng)運(yùn)營(yíng),你可以點(diǎn)擊>>>“互聯(lián)網(wǎng)運(yùn)營(yíng)就業(yè)班”了解課程詳情;
數(shù)據(jù)分析咨詢(xún)請(qǐng)掃描二維碼
若不方便掃碼,搜微信號(hào):CDAshujufenxi
SQL Server 中 CONVERT 函數(shù)的日期轉(zhuǎn)換:從基礎(chǔ)用法到實(shí)戰(zhàn)優(yōu)化 在 SQL Server 的數(shù)據(jù)處理中,日期格式轉(zhuǎn)換是高頻需求 —— 無(wú)論 ...
2025-09-18MySQL 大表拆分與關(guān)聯(lián)查詢(xún)效率:打破 “拆分必慢” 的認(rèn)知誤區(qū) 在 MySQL 數(shù)據(jù)庫(kù)管理中,“大表” 始終是性能優(yōu)化繞不開(kāi)的話(huà)題。 ...
2025-09-18CDA 數(shù)據(jù)分析師:表結(jié)構(gòu)數(shù)據(jù) “獲取 - 加工 - 使用” 全流程的賦能者 表結(jié)構(gòu)數(shù)據(jù)(如數(shù)據(jù)庫(kù)表、Excel 表、CSV 文件)是企業(yè)數(shù)字 ...
2025-09-18DSGE 模型中的 Et:理性預(yù)期算子的內(nèi)涵、作用與應(yīng)用解析 動(dòng)態(tài)隨機(jī)一般均衡(Dynamic Stochastic General Equilibrium, DSGE)模 ...
2025-09-17Python 提取 TIF 中地名的完整指南 一、先明確:TIF 中的地名有哪兩種存在形式? 在開(kāi)始提取前,需先判斷 TIF 文件的類(lèi)型 —— ...
2025-09-17CDA 數(shù)據(jù)分析師:解鎖表結(jié)構(gòu)數(shù)據(jù)特征價(jià)值的專(zhuān)業(yè)核心 表結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 規(guī)范存儲(chǔ)的結(jié)構(gòu)化數(shù)據(jù),如數(shù)據(jù)庫(kù)表、Excel 表、 ...
2025-09-17Excel 導(dǎo)入數(shù)據(jù)含缺失值?詳解 dropna 函數(shù)的功能與實(shí)戰(zhàn)應(yīng)用 在用 Python(如 pandas 庫(kù))處理 Excel 數(shù)據(jù)時(shí),“缺失值” 是高頻 ...
2025-09-16深入解析卡方檢驗(yàn)與 t 檢驗(yàn):差異、適用場(chǎng)景與實(shí)踐應(yīng)用 在數(shù)據(jù)分析與統(tǒng)計(jì)學(xué)領(lǐng)域,假設(shè)檢驗(yàn)是驗(yàn)證研究假設(shè)、判斷數(shù)據(jù)差異是否 “ ...
2025-09-16CDA 數(shù)據(jù)分析師:掌控表格結(jié)構(gòu)數(shù)據(jù)全功能周期的專(zhuān)業(yè)操盤(pán)手 表格結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 存儲(chǔ)的結(jié)構(gòu)化數(shù)據(jù),如 Excel 表、數(shù)據(jù) ...
2025-09-16MySQL 執(zhí)行計(jì)劃中 rows 數(shù)量的準(zhǔn)確性解析:原理、影響因素與優(yōu)化 在 MySQL SQL 調(diào)優(yōu)中,EXPLAIN執(zhí)行計(jì)劃是核心工具,而其中的row ...
2025-09-15解析 Python 中 Response 對(duì)象的 text 與 content:區(qū)別、場(chǎng)景與實(shí)踐指南 在 Python 進(jìn)行 HTTP 網(wǎng)絡(luò)請(qǐng)求開(kāi)發(fā)時(shí)(如使用requests ...
2025-09-15CDA 數(shù)據(jù)分析師:激活表格結(jié)構(gòu)數(shù)據(jù)價(jià)值的核心操盤(pán)手 表格結(jié)構(gòu)數(shù)據(jù)(如 Excel 表格、數(shù)據(jù)庫(kù)表)是企業(yè)最基礎(chǔ)、最核心的數(shù)據(jù)形態(tài) ...
2025-09-15Python HTTP 請(qǐng)求工具對(duì)比:urllib.request 與 requests 的核心差異與選擇指南 在 Python 處理 HTTP 請(qǐng)求(如接口調(diào)用、數(shù)據(jù)爬取 ...
2025-09-12解決 pd.read_csv 讀取長(zhǎng)浮點(diǎn)數(shù)據(jù)的科學(xué)計(jì)數(shù)法問(wèn)題 為幫助 Python 數(shù)據(jù)從業(yè)者解決pd.read_csv讀取長(zhǎng)浮點(diǎn)數(shù)據(jù)時(shí)的科學(xué)計(jì)數(shù)法問(wèn)題 ...
2025-09-12CDA 數(shù)據(jù)分析師:業(yè)務(wù)數(shù)據(jù)分析步驟的落地者與價(jià)值優(yōu)化者 業(yè)務(wù)數(shù)據(jù)分析是企業(yè)解決日常運(yùn)營(yíng)問(wèn)題、提升執(zhí)行效率的核心手段,其價(jià)值 ...
2025-09-12用 SQL 驗(yàn)證業(yè)務(wù)邏輯:從規(guī)則拆解到數(shù)據(jù)把關(guān)的實(shí)戰(zhàn)指南 在業(yè)務(wù)系統(tǒng)落地過(guò)程中,“業(yè)務(wù)邏輯” 是連接 “需求設(shè)計(jì)” 與 “用戶(hù)體驗(yàn) ...
2025-09-11塔吉特百貨孕婦營(yíng)銷(xiāo)案例:數(shù)據(jù)驅(qū)動(dòng)下的精準(zhǔn)零售革命與啟示 在零售行業(yè) “流量紅利見(jiàn)頂” 的當(dāng)下,精準(zhǔn)營(yíng)銷(xiāo)成為企業(yè)突圍的核心方 ...
2025-09-11CDA 數(shù)據(jù)分析師與戰(zhàn)略 / 業(yè)務(wù)數(shù)據(jù)分析:概念辨析與協(xié)同價(jià)值 在數(shù)據(jù)驅(qū)動(dòng)決策的體系中,“戰(zhàn)略數(shù)據(jù)分析”“業(yè)務(wù)數(shù)據(jù)分析” 是企業(yè) ...
2025-09-11Excel 數(shù)據(jù)聚類(lèi)分析:從操作實(shí)踐到業(yè)務(wù)價(jià)值挖掘 在數(shù)據(jù)分析場(chǎng)景中,聚類(lèi)分析作為 “無(wú)監(jiān)督分組” 的核心工具,能從雜亂數(shù)據(jù)中挖 ...
2025-09-10統(tǒng)計(jì)模型的核心目的:從數(shù)據(jù)解讀到?jīng)Q策支撐的價(jià)值導(dǎo)向 統(tǒng)計(jì)模型作為數(shù)據(jù)分析的核心工具,并非簡(jiǎn)單的 “公式堆砌”,而是圍繞特定 ...
2025-09-10