Python 中的鴨子類型和猴子補丁

来源:https://www.cnblogs.com/alwaysbeta/archive/2022/04/11/16133086.html
-Advertisement-
Play Games

原文鏈接: Python 中的鴨子類型和猴子補丁 大家好,我是老王。 Python 開發者可能都聽說過鴨子類型和猴子補丁這兩個詞,即使沒聽過,也大概率寫過相關的代碼,只不過並不瞭解其背後的技術要點是這兩個詞而已。 我最近在面試候選人的時候,也會問這兩個概念,很多人答的也並不是很好。但是當我向他們解釋 ...


原文鏈接: Python 中的鴨子類型和猴子補丁

大家好,我是老王。

Python 開發者可能都聽說過鴨子類型猴子補丁這兩個詞,即使沒聽過,也大概率寫過相關的代碼,只不過並不瞭解其背後的技術要點是這兩個詞而已。

我最近在面試候選人的時候,也會問這兩個概念,很多人答的也並不是很好。但是當我向他們解釋完之後,普遍都會恍然大悟:“哦,是這個啊,我用過”。

所以,我決定來寫一篇文章,探討一下這兩個技術。

鴨子類型

引用維基百科中的一段解釋:

鴨子類型duck typing)在程式設計中是動態類型的一種風格。在這種風格中,一個對象有效的語義,不是由繼承自特定的類或實現特定的介面,而是由"當前方法和屬性的集合"決定。

更通俗一點的說:

當看到一隻鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那麼這隻鳥就可以被稱為鴨子。

也就是說,在鴨子類型中,關註點在於對象的行為,能作什麼;而不是關註對象所屬的類型。

我們看一個例子,更形象地展示一下:

# 這是一個鴨子(Duck)類
class Duck:
    def eat(self):
        print("A duck is eating...")

    def walk(self):
        print("A duck is walking...")


# 這是一個狗(Dog)類
class Dog:
    def eat(self):
        print("A dog is eating...")

    def walk(self):
        print("A dog is walking...")


def animal(obj):
    obj.eat()
    obj.walk()


if __name__ == '__main__':
    animal(Duck())
    animal(Dog())

程式輸出:

A duck is eating...
A duck is walking...
A dog is eating...
A dog is walking...

Python 是一門動態語言,沒有嚴格的類型檢查。只要 DuckDog 分別實現了 eatwalk 方法就可以直接調用。

再比如 list.extend() 方法,除了 list 之外,dicttuple 也可以調用,只要它是可迭代的就都可以調用。

看過上例之後,應該對「對象的行為」和「對象所屬的類型」有更深的體會了吧。

再擴展一點,其實鴨子類型和介面挺像的,只不過沒有顯式定義任何介面。

比如用 Go 語言來實現鴨子類型,代碼是這樣的:

package main

import "fmt"

// 定義介面,包含 Eat 方法
type Duck interface {
	Eat()
}

// 定義 Cat 結構體,並實現 Eat 方法
type Cat struct{}

func (c *Cat) Eat() {
	fmt.Println("cat eat")
}

// 定義 Dog 結構體,並實現 Eat 方法
type Dog struct{}

func (d *Dog) Eat() {
	fmt.Println("dog eat")
}

func main() {
	var c Duck = &Cat{}
	c.Eat()

	var d Duck = &Dog{}
	d.Eat()

	s := []Duck{
		&Cat{},
		&Dog{},
	}
	for _, n := range s {
		n.Eat()
	}
}

通過顯式定義一個 Duck 介面,每個結構體實現介面中的方法來實現。

猴子補丁

猴子補丁Monkey Patch)的名聲不太好,因為它會在運行時動態修改模塊、類或函數,通常是添加功能或修正缺陷。

猴子補丁在記憶體中發揮作用,不會修改源碼,因此只對當前運行的程式實例有效。

但如果濫用的話,會導致系統難以理解和維護。

主要有兩個問題:

  1. 補丁會破壞封裝,通常與目標緊密耦合,因此很脆弱
  2. 打了補丁的兩個庫可能相互牽絆,因為第二個庫可能會撤銷第一個庫的補丁

所以,它被視為臨時的變通方案,不是集成代碼的推薦方式。

按照慣例,還是舉個例子來說明:

# 定義一個Dog類
class Dog:
    def eat(self):
        print("A dog is eating ...")


# 在類的外部給 Dog 類添加猴子補丁
def walk(self):
    print("A dog is walking ...")


Dog.walk = walk

# 調用方式與類的內部定義的屬性和方法一樣
dog = Dog()
dog.eat()
dog.walk()

程式輸出:

A dog is eating ...
A dog is walking ...

這裡相當於在類的外部給 Dog 類增加了一個 walk 方法,而調用方式與類的內部定義的屬性和方法一樣。

再舉一個比較實用的例子,比如我們常用的 json 標準庫,如果說想用性能更高的 ujson 代替的話,那勢必需要將每個文件的引入:

import json

改成:

import ujson as json

如果這樣改起來成本就比較高了。這個時候就可以考慮使用猴子補丁,只需要在程式入口加上:

import json  
import ujson  


def monkey_patch_json():  
    json.__name__ = 'ujson'  
    json.dumps = ujson.dumps  
    json.loads = ujson.loads  


monkey_patch_json()

這樣在以後調用 dumpsloads 方法的時候就是調用的 ujson 包,還是很方便的。

但猴子補丁就是一把雙刃劍,問題也在上文中提到了,看需,謹慎使用吧。

以上就是本文的全部內容,如果覺得還不錯的話,歡迎點贊轉發關註,感謝支持。


推薦閱讀:


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ​1. 什麼是邊框圖片 為了實現豐富多彩的邊框效果,在css3中,新增了 border-image屬性,這個新增屬性允許指定一副圖像作為元素的邊框。​ 2. 邊框圖片的使用場景 盒子大小不一,但是邊框樣式相同,此時就需要邊框圖片來完成,不是背景圖片,而是用邊框圖片來實現。 3. 邊框圖片的切圖原理 ...
  • 1 簡介 jsx(JavaScript XML),即可拓展的JavaScript,是react定義的一種類似於XML的js擴展語法:JS+XML。它本質上是React.createElement(type,config,...children)的語法糖,主要用於創建React元素,生成虛擬DOM 2 ...
  • 準備工作 npm i wangeditor --save npm i caret-pos --save 組件: <!--富文本--> <div :id="editorEleId" @keydown="onKeyDownInput($event)" @click="onClickEditor" ></ ...
  • 表達式全集 字元 描述 \ 將下一個字元標記為一個特殊字元、或一個原義字元、或一個向後引用、或一個八進位轉義符。例如,“n”匹配字元“n”。“\n”匹配一個換行符。串列“\\”匹配“\”而“\(”則匹配“(”。 ^ 匹配輸入字元串的開始位置。如果設置了RegExp對象的Multiline屬性,^也匹 ...
  • 觀察者模式是什麼 觀察者模式是一種行為設計模式, 允許一個對象將其狀態的改變通知其他對象。觀察者模式允許你定義一種訂閱機制, 可在對象事件發生時通知多個觀察者。 為什麼用觀察者模式 當一個對象狀態改變時需要改變其他對象,可使用觀察者模式。它定義對象間的一對多的依賴關係,當一個對象的狀態發生改變時,所 ...
  • 博客推行版本更新,成果積累制度,已經寫過的博客還會再次更新,不斷地琢磨,高質量高數量都是要追求的,工匠精神是學習必不可少的精神。因此,大家有何建議歡迎在評論區踴躍發言,你們的支持是我最大的動力,你們敢投,我就敢肝 ...
  • 責任鏈模式又稱職責鏈模式,屬於行為型模式;在責任鏈模式里,很多對象由每一個對象對其下家的引用而連接起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。發出這個請求的客戶端並不指導鏈上的哪一個對象最終處理這個請求,這使得系統可以在不影響客戶端的情況下動態地重新組織鏈和分配責任。 責 ...
  • 博客推行版本更新,成果積累制度,已經寫過的博客還會再次更新,不斷地琢磨,高質量高數量都是要追求的,工匠精神是學習必不可少的精神。因此,大家有何建議歡迎在評論區踴躍發言,你們的支持是我最大的動力,你們敢投,我就敢肝 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...