ホームページ  >  記事  >  バックエンド開発  >  Python でのダック タイピングとモンキー パッチ

Python でのダック タイピングとモンキー パッチ

WBOY
WBOY転載
2023-04-16 22:55:011379ブラウズ

皆さんこんにちは、ラオ・ワンです。

Python 開発者は、ダック タイピングとモンキー パッチという用語を聞いたことがあるかもしれません。たとえ聞いたことがなくても、関連するコードを書いたことはあるでしょうが、その背後にある技術的なポイントは理解していません。たった 2 つの単語だけです。

最近、候補者と面接したときに、この 2 つの概念についても質問しましたが、多くの人の答えはあまり良くありませんでした。しかし、私がそれを説明すると、彼らはたいてい突然、「ああ、これだ、前に使ったことがある」と気づきます。

そこで、これら 2 つのテクノロジーについて説明する記事を書くことにしました。

ダック タイピング

Wikipedia からの説明の引用:

ダック タイピングは、プログラミングにおける動的型付けのスタイルです。このスタイルでは、オブジェクトの有効なセマンティクスは、特定のクラスからの継承や特定のインターフェイスの実装によってではなく、「現在のメソッドとプロパティのセット」によって決まります。

より一般的に言うと、

鳥がアヒルのように歩き、アヒルのように泳ぎ、アヒルのように鳴くのを見たら、その鳥をアヒルと呼ぶことができます。

言い換えれば、ダックタイピングでは、オブジェクトが属する型ではなく、オブジェクトの動作とそのオブジェクトが実行できることに焦点が当てられます。

これをよりわかりやすく示すために例を見てみましょう:

# 这是一个鸭子(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() メソッドです。反復可能である限り、リストに加えて、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 インターフェイスと、そのインターフェイス内のメソッドを実装する各構造体を明示的に定義することによって実装されます。 。

モンキー パッチ

モンキー パッチは、通常は機能の追加や欠陥の修正を目的として、実行時にモジュール、クラス、または関数を動的に変更するため、悪い評判があります。

モンキー パッチはメモリ内で動作し、ソース コードを変更しないため、現在実行中のプログラム インスタンスに対してのみ有効です。

しかし、悪用されると、システムの理解と維持が困難になります。

主な問題は 2 つあります。

  • パッチはカプセル化を破壊し、通常はターゲットと密接に結合しているため脆弱です。
  • 2 つのパッチが適用されたライブラリは、 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

Change to:

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()

を追加するだけです。こうすることで、将来ダンプ メソッドとロード メソッドを呼び出すときに、ujson パッケージを呼び出すことになります。 、それでも非常に便利です。

ただし、モンキー パッチは諸刃の剣です。問題は上でも述べたとおりです。必要に応じて慎重に使用してください。

以上がPython でのダック タイピングとモンキー パッチの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事は51cto.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。