Maison développement back-end Tutoriel Python Comment développer Monkey Patch en programmation Python

Comment développer Monkey Patch en programmation Python

Mar 02, 2017 pm 04:04 PM

La méthode Monkey Patch fait référence à l'ajout de code pendant le processus d'exécution du programme en ajoutant des classes ou des modules sans modifier le code original du programme. Ce qui suit est une explication plus détaillée de la méthode de développement Monkey Patch dans la programmation Python. L'application du

Monkey patch consiste à modifier le code existant au moment de l'exécution pour atteindre l'objectif du hot patch. Cette technique est largement utilisée dans Eventlet pour remplacer des composants de la bibliothèque standard, tels que les sockets. Tout d’abord, jetons un coup d’œil à l’implémentation la plus simple de Monkey Patch.

class Foo(object):
  def bar(self):
    print 'Foo.bar'

def bar(self):
  print 'Modified bar'

Foo().bar()

Foo.bar = bar

Foo().bar()
Copier après la connexion

Étant donné que l'espace de noms en Python est ouvert et implémenté via dict, il est facile d'atteindre l'objectif de l'application de correctifs.

Espace de noms Python

Python a plusieurs espaces de noms, à savoir

  • locals

  • globaux

  • builtin

Les variables définies dans les fonctions appartiennent aux variables locales, tandis que les fonctions définies dans les modules appartiennent aux variables globales.

Importation de module Python et recherche de nom

Lorsque nous importons un module, Python fera les choses suivantes

  • Importer un module

  • et ajoutez l'objet module à sys.modules. Les importations ultérieures du module seront obtenues directement à partir du dict

  • . L'objet module est ajouté au dict global

Lorsque nous référençons un module, il sera recherché à partir des globaux. Si nous voulons remplacer un module standard ici, nous devons faire les deux choses suivantes

Ajouter notre propre module à sys.modules et remplacer le module d'origine. Si le module remplacé n'a pas été chargé, nous devons d'abord le charger, sinon le module standard sera chargé la première fois. (Il existe un hook d'importation disponible ici, mais cela nous oblige à implémenter le hook nous-mêmes. Nous pouvons également utiliser cette méthode pour hooker l'importation de module)
Si le module remplacé fait référence à d'autres modules, alors nous devons également le remplacer, mais ici, nous pouvons modifier le dict des globals et ajouter notre module aux globals pour accrocher ces modules référencés.
Implémentation d'Eventlet Patcher

Jetons maintenant un coup d'œil au code d'appel de Patcher dans l'eventlet. Ce code crée un patch singe pour la ftplib standard et remplace le GreenSocket standard de l'événement. événementlet.

from eventlet import patcher

# *NOTE: there might be some funny business with the "SOCKS" module
# if it even still exists
from eventlet.green import socket

patcher.inject('ftplib', globals(), ('socket', socket))

del patcher

inject函数会将eventlet的socket模块注入标准的ftplib中,globals dict被传入以做适当的修改。

让我们接着来看一下inject的实现。

__exclude = set(('__builtins__', '__file__', '__name__'))

def inject(module_name, new_globals, *additional_modules):
  """Base method for "injecting" greened modules into an imported module. It
  imports the module specified in *module_name*, arranging things so
  that the already-imported modules in *additional_modules* are used when
  *module_name* makes its imports.

  *new_globals* is either None or a globals dictionary that gets populated
  with the contents of the *module_name* module. This is useful when creating
  a "green" version of some other module.

  *additional_modules* should be a collection of two-element tuples, of the
  form (, ). If it's not specified, a default selection of
  name/module pairs is used, which should cover all use cases but may be
  slower because there are inevitably redundant or unnecessary imports.
  """
  if not additional_modules:
    # supply some defaults
    additional_modules = (
      _green_os_modules() +
      _green_select_modules() +
      _green_socket_modules() +
      _green_thread_modules() +
      _green_time_modules())

  ## Put the specified modules in sys.modules for the duration of the import
  saved = {}
  for name, mod in additional_modules:
    saved[name] = sys.modules.get(name, None)
    sys.modules[name] = mod

  ## Remove the old module from sys.modules and reimport it while
  ## the specified modules are in place
  old_module = sys.modules.pop(module_name, None)
  try:
    module = __import__(module_name, {}, {}, module_name.split('.')[:-1])

    if new_globals is not None:
      ## Update the given globals dictionary with everything from this new module
      for name in dir(module):
        if name not in __exclude:
          new_globals[name] = getattr(module, name)

    ## Keep a reference to the new module to prevent it from dying
    sys.modules['__patched_module_' + module_name] = module
  finally:
    ## Put the original module back
    if old_module is not None:
      sys.modules[module_name] = old_module
    elif module_name in sys.modules:
      del sys.modules[module_name]

    ## Put all the saved modules back
    for name, mod in additional_modules:
      if saved[name] is not None:
        sys.modules[name] = saved[name]
      else:
        del sys.modules[name]

  return module
Copier après la connexion

Les commentaires expliquent clairement l'intention du code. Le code est relativement facile à comprendre. Il existe une fonction __import__, qui fournit un nom de module (chaîne) pour charger un module. Le nom que nous fournissons lors de l’importation ou du rechargement est un objet.

if new_globals is not None:
  ## Update the given globals dictionary with everything from this new module
  for name in dir(module):
    if name not in __exclude:
      new_globals[name] = getattr(module, name)
Copier après la connexion

La fonction de ce code est d'ajouter des objets en ftplib standard au module ftplib de eventlet. Parce que nous avons appelé inject dans eventlet.ftplib et transmis les globals, et dans inject, nous __importons manuellement le module et n'avons obtenu qu'un seul objet de module, donc les objets du module ne seront pas ajoutés aux globals et devront être ajoutés manuellement.
La raison pour laquelle from ftplib import * n'est pas utilisé ici est probablement parce qu'il ne peut pas remplacer complètement ftplib. Parce que from...import * importera les symboles publics selon la liste __all__ dans __init__.py, et de cette manière, les symboles privés commençant par un trait de soulignement ne seront pas importés et une correction complète ne pourra pas être réalisée.

Pour plus d'articles liés aux méthodes de développement de Monkey Patch dans la programmation Python, veuillez faire attention au site Web PHP chinois !


Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Comment résoudre le problème des autorisations rencontré lors de la visualisation de la version Python dans le terminal Linux? Comment résoudre le problème des autorisations rencontré lors de la visualisation de la version Python dans le terminal Linux? Apr 01, 2025 pm 05:09 PM

Solution aux problèmes d'autorisation Lors de la visualisation de la version Python dans Linux Terminal Lorsque vous essayez d'afficher la version Python dans Linux Terminal, entrez Python ...

Comment enseigner les bases de la programmation novice en informatique dans le projet et les méthodes axées sur les problèmes dans les 10 heures? Comment enseigner les bases de la programmation novice en informatique dans le projet et les méthodes axées sur les problèmes dans les 10 heures? Apr 02, 2025 am 07:18 AM

Comment enseigner les bases de la programmation novice en informatique dans les 10 heures? Si vous n'avez que 10 heures pour enseigner à l'informatique novice des connaissances en programmation, que choisissez-vous d'enseigner ...

Comment copier efficacement la colonne entière d'une dataframe dans une autre dataframe avec différentes structures dans Python? Comment copier efficacement la colonne entière d'une dataframe dans une autre dataframe avec différentes structures dans Python? Apr 01, 2025 pm 11:15 PM

Lorsque vous utilisez la bibliothèque Pandas de Python, comment copier des colonnes entières entre deux frames de données avec différentes structures est un problème courant. Supposons que nous ayons deux dats ...

Comment éviter d'être détecté par le navigateur lors de l'utilisation de Fiddler partout pour la lecture de l'homme au milieu? Comment éviter d'être détecté par le navigateur lors de l'utilisation de Fiddler partout pour la lecture de l'homme au milieu? Apr 02, 2025 am 07:15 AM

Comment éviter d'être détecté lors de l'utilisation de FiddlereVerywhere pour les lectures d'homme dans le milieu lorsque vous utilisez FiddlereVerywhere ...

Comment Uvicorn écoute-t-il en permanence les demandes HTTP sans servir_forever ()? Comment Uvicorn écoute-t-il en permanence les demandes HTTP sans servir_forever ()? Apr 01, 2025 pm 10:51 PM

Comment Uvicorn écoute-t-il en permanence les demandes HTTP? Uvicorn est un serveur Web léger basé sur ASGI. L'une de ses fonctions principales est d'écouter les demandes HTTP et de procéder ...

Comment créer dynamiquement un objet via une chaîne et appeler ses méthodes dans Python? Comment créer dynamiquement un objet via une chaîne et appeler ses méthodes dans Python? Apr 01, 2025 pm 11:18 PM

Dans Python, comment créer dynamiquement un objet via une chaîne et appeler ses méthodes? Il s'agit d'une exigence de programmation courante, surtout si elle doit être configurée ou exécutée ...

See all articles