精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

__missing__()的實現原理

科技綠洲 ? 來源:Python實用寶典 ? 作者:Python實用寶典 ? 2023-10-30 14:58 ? 次閱讀

上篇文章中,我有一個核心的發現:Python 內置類型的特殊方法(含魔術方法與其它方法)由 C 語言獨立實現,在 Python 層面不存在調用關系。

但是,文中也提到了一個例外:一個非常神秘的魔術方法。

這個方法非常不起眼,用途狹窄,我幾乎從未注意過它,然而,當發現它可能是上述“定律”的唯一例外情況時,我認為值得再寫一篇文章來詳細審視一下它。

本文主要關注的問題有:

(1) missing ()到底是何方神圣?

(2) missing ()有什么特別之處?擅長“大變活人”魔術?

(3) missing ()是否真的是上述發現的例外?如果是的話,為什么會有這種特例?

1、有點價值的__missing__()

從普通的字典中取值時,可能會出現 key 不存在的情況:

dd = {'name':'PythonCat'}
dd.get('age')        # 結果:None
dd.get('age', 18)    # 結果:18
dd['age']            # 報錯 KeyError
dd.__getitem__('age')  # 等同于 dd['age']

圖片

對于 get() 方法,它是有返回值的,而且可以傳入第二個參數,作為 key 不存在時的返回內容,因此還可以接受。但是,另外兩種寫法都會報錯。

為了解決后兩種寫法的問題,就可以用到 missing () 魔術方法。

現在,假設我們有一個這樣的訴求:從字典中取某個 key 對應的 value,如果有值則返回值,如果沒有值則插入 key,并且給它一個默認值(例如一個空列表)。

如果用原生的 dict,并不太好實現,但是,Python 提供了一個非常好用的擴展類collections.defaultdict

圖片

如圖所示,當取不存在的 key 時,沒有再報 KeyError,而是默認存入到字典中。

為什么 defaultdict 可以做到這一點呢?

原因是 defaultdict 在繼承了內置類型 dict 之后,還定義了一個 missing () 方法,當 __getitem__取不存在的值時,它就會調用入參中傳入的工廠函數(上例是調用 list(),創建空列表)。

作為最典型的示例,defaultdict 在文檔注釋中寫到:

圖片

簡而言之,** missing ()的主要作用就是由__getitem__在缺失 key 時調用,從而避免出現 KeyError。**

另外一個典型的使用例子是collections.Counter,它也是 dict 的子類,在取未被統計的 key 時,返回計數 0:

圖片

2、神出鬼沒的__missing__()

由上可知, missing ()在__getitem__()取不到值時會被調用,但是,我不經意間還發現了一個細節:** getitem ()在取不到值時,并不一定會調用__missing__()。**

這是因為它并非內置類型的必要屬性,并沒有在字典基類中被預先定義。

如果你直接從 dict 類型中取該屬性值,會報屬性不存在:AttributeError: type object 'object' has no attribute '__missing__'。

使用 dir() 查看,發現確實不存在該屬性:

圖片

如果從 dict 的父類即 object 中查看,也會發現同樣的結果。

這是怎么回事呢?為什么在 dict 和 object 中都沒有__missing__屬性呢?

然而,查閱最新的官方文檔,object 中分明包含這個屬性:

圖片

出處:https://docs.python.org/3/reference/datamodel.html?highlight= missing #object.missing

也就是說,理論上 object 類中會預定義__missing__,其文檔證明了這一點,然而實際上它并沒有被定義!文檔與現實出現了偏差!

如此一來,當 dict 的子類(例如 defaultdict 和 Counter)在定義__missing__ 時,這個魔術方法事實上只屬于該子類,也就是說,它是一個誕生于子類中的魔術方法!

據此,我有一個不成熟的猜想: getitem ()會判斷當前對象是否是 dict 的子類,且是否擁有__missing__(),然后才會去調用它(如果父類中也有該方法,則不會先作判斷,而是直接就調用了)。

我在交流群里說出了這個猜想,有同學很快在 CPython 源碼中找到驗證:

圖片

而這就有意思了, 在內置類型的子類上才存在的魔術方法, 縱觀整個 Python 世界,恐怕再難以找出第二例。

我突然有一個聯想:這神出鬼沒的__missing__(),就像是一個擅長玩“大變活人”的魔術師,先讓觀眾在外面透過玻璃看到他(即官方文檔),然而揭開門時,他并不在里面(即內置類型),再變換一下道具,他又完好無損就出現了(即 dict 的子類)。

3、被施魔法的__missing__()

missing () 的神奇之處,除了它本身會變“魔術”之外,它還需要一股強大的“魔法”才能驅動。

上篇文章中,我發現原生的魔術方法間相互獨立,它們在 C 語言界面可能有相同的核心邏輯,但是在 Python 語言界面,卻并不存在著調用關系:

圖片

魔術方法的這種“老死不相往來”的表現,違背了一般的代碼復用原則,也是導致內置類型的子類會出現某些奇怪表現的原因。

官方 Python 寧肯提供新的 UserString、UserList、UserDict 子類,也不愿意復用魔術方法,唯一合理的解釋似乎是令魔術方法相互調用的代價太大。

但是,對于特例__missing__(),Python 卻不得不妥協,不得不付出這種代價!

missing () 是魔術方法的“ 二等公民 ”,它沒有獨立的調用入口,只能被動地由 getitem () 調用,即__missing__() 依賴于__getitem__()。

不同于那些“ 一等公民 ”,例如 init ()、 enter ()、 len ()、 eq () 等等,它們要么是在對象生命周期或執行過程的某個節點被觸發,要么由某個內置函數或操作符觸發,這些都是相對獨立的事件,無所依賴。

** missing () 依賴于__getitem__(),才能實現方法調用;而 getitem () 也要依賴 missing (),才能實現完整功能。**

為了實現這一點, getitem ()在解釋器代碼中開了個后門,從 C 語言界面折返回 Python 界面,去調用那個名為“ missing ”的特定方法。

圖片

而這就是真正的“魔法”了,目前為止, missing ()似乎是唯一一個享受了此等待遇的魔術方法!

4、小結

Python 的字典提供了兩種取值的內置方法,即__getitem__() 和 get(),當取值不存在時,它們的處理策略是不一樣的:前者會報錯KeyError,而后者會返回 None。

為什么 Python 要提供兩個不同的方法呢?或者應該問,為什么 Python 要令這兩個方法做出不一樣的處理呢?

這可能有一個很復雜(也可能是很簡單)的解釋,本文暫不深究了。

不過有一點是可以確定的:即原生 dict 類型簡單粗暴地拋KeyError的做法有所不足。

為了讓字典類型有更強大的表現(或者說讓__getitem__()作出 get() 那樣的表現),Python 讓字典的子類可以定義__missing__(),供__getitem__()查找調用。

本文梳理了__missing__()的實現原理,從而揭示出它并非是一個毫不起眼的存在,恰恰相反,它是唯一一個打破了魔術方法間壁壘,支持被其它魔術方法調用的特例!

Python 為了維持魔術方法的獨立性,不惜煞費苦心地引入了 UserString、UserList、UserDict 這些派生類,但是對于 missing (),它卻選擇了妥協。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 函數
    +關注

    關注

    3

    文章

    4307

    瀏覽量

    62433
  • python
    +關注

    關注

    56

    文章

    4782

    瀏覽量

    84461
  • C 語言
    +關注

    關注

    0

    文章

    18

    瀏覽量

    14223
  • key
    key
    +關注

    關注

    0

    文章

    48

    瀏覽量

    12814
收藏 人收藏

    評論

    相關推薦

    接上開發板后顯示EEPROM missing

    接上開發板后,設備管理其中顯示:68013-EEPROMmissing在下載程序后卻出現了,這樣一種情況:本應該在下載程序后,68013-EEPROM missing的消息應當消失,但是在這里卻沒有發生上述現象
    發表于 11-21 18:22

    keil中警告missing return value

    今天遇到一個奇怪的問題:{:14:} keil編譯出現DHA200A.C(820): warning C290: missing return value警告!此函數是void型main函數并無
    發表于 08-30 16:33

    仿真時,LED出現missing是怎么回事

    仿真時,LED出現missing是怎么回事
    發表于 04-17 19:16

    protues仿真出現元器件missing的問題

    protues錯誤改了之后出現元器件missing的問題如何解決
    發表于 07-15 20:56

    the #endif for this directive is missing 這個錯誤怎么解決啊?

    Error[Pe037]: the #endif for this directive is missing這個錯誤怎么解決?。?/div>
    發表于 07-22 18:27

    在設計FPGA程序時,誰遇到過如下的警告啊: One or more signals are missing in the process sensitivity list.

    請問。在設計FPGA程序時,誰遇到過如下的警告啊: One or more signals are missing in the process sensitivity list.
    發表于 05-17 15:57

    mixed model MCS8051.DLL failed to authorize - Missing or invalid Customer Key.. [U1]這個啥情況求幫忙

    mixed model MCS8051.DLL failed to authorize - Missing or invalid Customer Key.. [U1]求幫忙
    發表于 01-05 12:24

    ccs6.1.2安裝提示Error:missing value to go with key是為什么?

    您 好! 官網下載的最新版的離線的ccs6.1,選好安裝路徑點next后提示: Error:missing value to go with key,請問這是為什么? 系統環境為WIN7旗艦版64位;已關閉殺毒軟件的文件系統實時防護,無法關閉其所有功能;安裝路徑不包含中文字符。
    發表于 05-15 09:41

    Keil編譯出現“main.c(16): error C129: missing ';' before 'num'”怎么解決

    Keil編譯時提示“main.c(16): error C129: missing ‘;’ before ‘num’”折騰了很久才知道是前面的“typedef unsigned char u8
    發表于 02-16 06:50

    MDK打開工程提示Missing Device是什么原因?

    MDK打開工程提示Missing Device 這個是什么原因
    發表于 08-18 08:28

    E5515C-14 Wireless Communicati

    need to be inspected for 2 missing washers on the DSP fan assembly (detailed pictures are below). If the washers are missing then t
    發表于 08-21 11:54 ?9次下載

    NTLDR is missing開機故障如何處理

    NTLDR is missing開機故障如何處理 故障現象:開機自檢一切正常,可是在進入系統,也就是進行系統引導的時候卡住了,顯示
    發表于 03-10 11:46 ?9269次閱讀

    EFM8SB1芯科單片機調試 打開NoOverlay.hwconf文件報錯

    loading the device: missing property: cslib.thresholdsettings.activesensordelta missing prop...
    發表于 11-25 19:36 ?9次下載
    EFM8SB1芯科單片機調試 打開NoOverlay.hwconf文件報錯

    Keil編譯時提示“main.c(16): error C129: missing ';' before 'num'”

    Keil編譯時提示“main.c(16): error C129: missing ‘;’ before ‘num’”折騰了很久才知道是前面的“typedef unsigned char u8
    發表于 12-17 18:10 ?16次下載
    Keil編譯時提示“main.c(16): error C129: <b class='flag-5'>missing</b> ';' before 'num'”

    Missing Container Metrics容器指標收集工具

    ./oschina_soft/missing-container-metrics.zip
    發表于 05-12 14:24 ?1次下載
    <b class='flag-5'>Missing</b> Container Metrics容器指標收集工具