成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

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

大家好,我是老王。

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 是一門動態語言,沒有嚴格的類型檢查。只要 Duck 和 Dog 分別實現了 eat 和 walk 方法就可以直接調用。

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

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

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

比如用 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)的名聲不太好,因為它會在運行時動態修改模塊、類或函數,通常是添加功能或修正缺陷。

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

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

主要有兩個問題:

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

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

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

# 定義一個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()

這樣在以后調用 dumps 和 loads 方法的時候就是調用的 ujson 包,還是很方便的。

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

責任編輯:武曉燕 來源: AlwaysBeta
相關推薦

2017-09-13 00:07:05

Python編程語言動態語言

2021-07-02 06:54:45

面試鴨子類型

2024-04-15 00:02:00

Java補丁技術

2021-05-21 09:01:56

Python繼承多態

2021-10-17 18:54:40

Python定義使用

2021-02-05 11:35:03

原子類數值變量

2023-10-27 08:34:46

PythonJava優勢

2020-12-11 08:41:00

高可用Chaos 系統

2009-12-04 09:14:05

.NET 4.0

2022-04-06 09:10:03

抽象類型普通類型Swift

2024-11-14 10:00:00

Python繼承

2020-12-11 11:11:44

原子類JavaCAS

2011-07-11 14:36:05

JAVA

2023-12-01 08:54:50

Java原子類型

2020-04-10 08:00:08

Kubernetes補丁pod

2021-04-15 21:21:59

代碼熱Python函數

2011-06-08 13:50:39

C#類型轉換

2024-10-08 08:00:00

2020-10-26 07:16:10

MySQLSchema數據

2021-03-27 10:54:34

Python函數代碼
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩aⅴ在线观看 | 日日综合| 亚洲欧美日韩精品久久亚洲区 | www.久久久.com | 亚洲一区免费视频 | 日韩免费视频一区二区 | 欧美一级做性受免费大片免费 | 欧美精品久久久久 | 伊人欧美视频 | 日韩av网址在线观看 | 狠狠入ady亚洲精品经典电影 | 国产农村妇女毛片精品久久麻豆 | 播放一级黄色片 | 91视视频在线观看入口直接观看 | 中文成人在线 | 最新日韩欧美 | av网站在线看 | 久久久久免费观看 | 中文字幕亚洲欧美日韩在线不卡 | 一区二区三区四区国产 | 免费观看的av | 天堂免费看片 | 成人av一区 | 精品国产久 | 成人午夜在线 | 91精品久久 | 福利二区 | 99国产精品久久久久老师 | 精品日韩一区 | 日韩免费高清视频 | 亚洲三级av | 亚洲高清一区二区三区 | 亚洲性人人天天夜夜摸 | 国产日韩视频在线 | 亚洲国产精品成人 | 欧美日韩一区在线 | 最新av中文字幕 | 波多野结衣二区 | 精品视频一区二区 | 亚洲一区二区三区在线播放 | 国产精品综合久久 |