Maison  >  Article  >  développement back-end  >  Typage de canard et patch de singe en Python

Typage de canard et patch de singe en Python

WBOY
WBOYavant
2023-04-16 22:55:011381parcourir

Bonjour à tous, je suis Lao Wang.

Les développeurs Python ont peut-être entendu parler des termes duck typing et Monkey patching. Même s'ils ne l'ont pas fait, ils ont probablement écrit du code associé, mais ils ne comprennent tout simplement pas les points techniques qui les sous-tendent.

Lorsque j'interviewais les candidats récemment, je posais également des questions sur ces deux concepts, et les réponses de beaucoup de gens n'étaient pas très bonnes. Mais après que je leur ai expliqué, ils réalisent généralement soudainement : « Oh, ça y est, je l'ai déjà utilisé.

J'ai donc décidé d'écrire un article pour discuter de ces deux technologies.

Duck typing

Citant une explication de Wikipédia :

Duck typing est un style de typage dynamique en programmation. Dans ce style, la sémantique effective d'un objet est déterminée non pas par l'héritage d'une classe spécifique ou par l'implémentation d'une interface spécifique, mais par « l'ensemble actuel de méthodes et de propriétés ».

Pour le dire de manière plus populaire :

Quand vous voyez un oiseau marcher comme un canard, nager comme un canard et cancaner comme un canard, alors cet oiseau peut être appelé un canard.

En d'autres termes, dans le typage canard, l'accent est mis sur le comportement de l'objet et ce qu'il peut faire plutôt que sur le type auquel l'objet appartient.

Regardons un exemple pour le montrer plus clairement :

# 这是一个鸭子(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())

Résultat du programme :

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

Python est un langage dynamique et n'a pas de vérification de type stricte. Tant que Duck et Dog implémentent respectivement les méthodes eat et walk, ils peuvent être appelés directement.

Un autre exemple est la méthode list.extend() En plus de list, dict et tuple peuvent également être appelés, à condition qu'ils soient itérables.

Après avoir lu l'exemple ci-dessus, vous devriez avoir une compréhension plus approfondie du « comportement des objets » et du « type d'objet ».

En développant un peu plus loin, le typage canard est en fait assez similaire aux interfaces, sauf qu'aucune interface n'est explicitement définie.

Par exemple, si vous utilisez le langage Go pour implémenter le typage Duck, le code est le suivant :

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

Il est implémenté en définissant explicitement une interface Duck et chaque structure implémentant les méthodes dans l'interface.

Monkey Patch

Monkey Patch a une mauvaise réputation car il modifie dynamiquement un module, une classe ou une fonction au moment de l'exécution, généralement pour ajouter des fonctionnalités ou corriger des défauts.

Le correctif Monkey fonctionne en mémoire et ne modifie pas le code source, il n'est donc efficace que pour l'instance de programme en cours d'exécution.

Mais en cas d'abus, cela rendra le système difficile à comprendre et à maintenir.

Il y a deux problèmes principaux :

  • Les correctifs rompent l'encapsulation, sont généralement étroitement couplés à la cible et sont donc vulnérables
  • Deux bibliothèques de correctifs peuvent s'emmêler l'une dans l'autre, car la deuxième bibliothèque peut annuler les premiers correctifs du bibliothèque

C'est donc considéré comme une solution de contournement temporaire et non comme un moyen recommandé d'intégrer le code.

Comme d'habitude, donnons un exemple pour illustrer :

# 定义一个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()

Sortie du programme :

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

Cela équivaut à ajouter une méthode walk à la classe Dog en dehors de la classe, et la méthode appelante est la même que les attributs et méthodes définis en interne dans la classe.

Prenons un autre exemple pratique, comme notre bibliothèque standard json couramment utilisée. Si nous voulons plutôt utiliser ujson avec des performances plus élevées, nous devons modifier l'importation de chaque fichier :

import json

en :

import ujson as json

If Le coût de la modification. ce serait relativement élevé. Pour le moment, vous pouvez envisager d'utiliser des patchs singe. Il vous suffit d'ajouter :

import json
import ujson


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


monkey_patch_json()

à l'entrée du programme. De cette façon, lors de l'appel des méthodes dumps etloads à l'avenir, ce sera le package ujson qui sera appelé. est toujours très pratique.

Mais le patch singe est une arme à double tranchant. Le problème est également mentionné ci-dessus. Utilisez-le avec prudence en fonction des besoins.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer