Ajout d'une Méthode à une Instance d'Objet
J'ai lu qu'il est possible d'ajouter une méthode à un objet existant (c'est à dire, pas dans la définition de la classe) en Python.
Je comprends qu'il n'est pas toujours bon de le faire. Mais comment peut-on faire cela?
Vous devez vous connecter pour publier un commentaire.
En Python, il y a une différence entre les fonctions et les méthodes liées.
Lié méthodes ont été "lié" (comment descriptive) à une instance, qui sera passé comme premier argument à chaque fois que la méthode est appelée.
Callables qui sont des attributs d'une classe (par opposition à une instance) sont encore indépendant, cependant, de sorte que vous pouvez modifier la définition de la classe à chaque fois que vous voulez:
Défini précédemment instances sont mises à jour (tant qu'ils n'ont pas remplacé l'attribut eux-mêmes):
Le problème vient quand vous voulez joindre une méthode à une seule instance:
La fonction n'est pas automatiquement lié quand il est connecté directement à une instance:
À la lie, nous pouvons utiliser la MethodType fonction des types de module:
Ce temps, les autres instances de la classe n'ont pas été touchés:
Plus d'informations peuvent être trouvées par la lecture sur les les descripteurs de et métaclasse programmation.
MethodType
, invoquer la descripteur de protocole manuellement et ont pour fonction de produire votre instance:barFighters.__get__(a)
produit une méthode liée pourbarFighters
lié àa
.descriptor protocol
vs la création d'unMethodType
à part peut-être d'être un peu plus lisible.classmethod
etstaticmethod
et d'autres descripteurs de trop. Il évite d'encombrer l'espace de noms avec encore une autre importation.a.barFighters = barFighters.__get__(a)
__get__
approche. Leimport types
semble plus explicite si.Module nouveau est déprécié depuis la version 2.6 de python et supprimé dans la version 3.0, utilisez types
voir http://docs.python.org/library/new.html
Dans l'exemple ci-dessous j'ai volontairement supprimé valeur de retour de
patch_me()
fonction.Je pense que donner la valeur de retour peut faire croire que le patch renvoie un nouvel objet, qui n'est pas vrai - il modifie l'arrivée. Sans doute cela peut faciliter une discipline d'utilisation de monkeypatching.
Préface - une note sur la compatibilité: autres réponses ne peuvent travailler en Python 2 - cette réponse devrait fonctionner parfaitement en Python 2 et 3. Si l'écriture de Python 3 seulement, vous pouvez laisser explicitement l'héritage de
object
, mais sinon, le code doit rester le même.Oui, c'est possible, Mais pas recommandé
Je ne le recommande pas. C'est une mauvaise idée. Ne pas le faire.
Voici un couple de raisons:
Donc, je vous suggère de ne pas le faire, sauf si vous avez une très bonne raison. Il est de loin préférable de définir la méthode correcte dans la définition de classe ou moins, de préférence, de singe-patch dans la classe, comme ceci:
Puisque c'est instructif, cependant, je vais vous montrer quelques façons de le faire.
Comment il peut être fait
Voici quelques code d'installation. Nous avons besoin d'une définition de classe. Il pourrait être importés, mais il n'a vraiment pas d'importance.
Créer une instance:
Créer une méthode pour ajouter:
Méthode de zéro (0) - utiliser le descripteur de la méthode,
__get__
En pointillés recherches sur les fonctions d'appel de la
__get__
méthode de la fonction de l'instance, la liaison de l'objet de la méthode et donc de la création d'une "méthode liée."et maintenant:
De la méthode des types.MethodType
D'abord, l'importation de types, à partir de laquelle nous allons obtenir la méthode constructeur:
Maintenant, nous ajoutons la méthode de l'instance. Pour ce faire, nous avons besoin de la MethodType constructeur de la
types
module (qui nous avons importé ci-dessus).L'argument de signature pour les types.MethodType est
(function, instance, class)
:et utilisation:
Méthode deux: lexical de liaison
Tout d'abord, nous créons une fonction wrapper qui lie la méthode de l'instance:
utilisation:
Méthode trois: functools.partielle
Une fonction partielle s'applique le premier argument(s) à une fonction (et éventuellement les arguments mots-clefs), et peuvent plus tard être appelé avec les autres arguments (et en remplaçant les arguments mots-clefs). Donc:
Cela fait sens quand on considère que les méthodes liées sont partielles des fonctions de l'instance.
Indépendant fonctionner comme un attribut de l'objet - pourquoi cela ne fonctionne pas:
Si nous essayons d'ajouter à la sample_method de la même façon que nous puissions l'ajouter à la classe, il est indépendant de l'instance, et ne prend pas l'implicite de soi en tant que premier argument.
Nous pouvons le rendre indépendant de la fonction de travail en faisant explicitement en passant l'instance (ou quoi que ce soit, étant donné que cette méthode n'est pas réellement utiliser le
self
argument variable), mais il ne serait pas cohérent avec la signature attendue de d'autres instances (si nous sommes singe de correction de cette instance):Conclusion
Vous savez maintenant plusieurs façons de pourrait le faire, mais en toute sincérité, - ne pas le faire.
__get__
méthode a également besoin de la classe que le paramètre suivant:sample_method.__get__(foo, Foo)
.types.MethodType
, lexical de liaison, etfunctools.partial
tous les travaux en Python 2 et 3, donc je ne vois pas beaucoup de point en appelant toutes les différences. Je suis au travail, et en regardant ce en passant, la seule différence est, je pense, en Python 3, nous pouvons implicitement hériter deobject
. Peut-être d'autres réponses doivent être mis à jour pour fonctionner en Python 3, mais depuis que leurs questions sont triviales, je ne suis pas sûr que cela a du sens de les appeler dans mon réponse - peut-être un commentaire de votre part sur ces réponses seraient plus proportionnelle...Je pense que les réponses ci-dessus manqué le point clé.
Nous allons avoir une classe avec une méthode:
Maintenant, nous allons jouer avec elle dans ipython:
Ok, donc m() en quelque sorte, devient indépendant de la méthode de Un. Mais est-ce vraiment comme ça?
Il s'avère que m() est juste une fonction de référence à laquelle est ajoutée à Un classe dictionary - il n'y a pas de magie. Alors pourquoi A. m nous donne un indépendant méthode? C'est parce que la dot n'est pas traduit par une simple recherche dans le dictionnaire. C'est de facto un appel de A.__class__.__getattribute__(A, 'm'):
Maintenant, je ne suis pas sûr de la partie supérieure de ma tête pourquoi la dernière ligne est imprimé deux fois, mais c'est clairement ce qui s y passe.
Maintenant, ce que la valeur par défaut __getattribute__ n'est qu'il vérifie si l'attribut est un soi-disant descripteur de ou pas, c'est à dire si elle met en œuvre un spécial __get__ méthode. Si elle met en œuvre cette méthode, puis ce qui est retourné est le résultat de l'appel qu' __get__ méthode. Revenir à la première version de notre Un classe, c'est ce que nous avons:
Et parce que Python fonctions de mettre en œuvre le descripteur de protocole, s'ils sont appelés sur le nom d'un objet, ils se lient à cet objet dans leur __get__ méthode.
Ok, donc comment faire pour ajouter une méthode à un objet existant? En supposant que vous n'avez pas l'esprit de rapiéçage de classe, c'est aussi simple que:
Puis B. m "devient" un indépendant méthode, grâce à la descripteur de la magie.
Et si vous souhaitez ajouter une méthode à un objet unique, alors vous avez à émuler les machines-même, en utilisant des types.MethodType:
Par la route:
En Python monkey patching fonctionne généralement à l'écrasement d'une classe ou d'une des fonctions de signature avec votre propre. Ci-dessous est un exemple de la Zope Wiki:
Que le code s'écraser/créer une méthode appelée parler à la classe. Dans Jeff Atwood est post récent sur monkey patching. Il montre un exemple en C# 3.0, ce qui est la langue que j'utilise pour le travail.
Vous pouvez utiliser lambda de se lier à une méthode d'une instance:
De sortie:
Il y a au moins deux façons de fixer une méthode d'une instance sans
types.MethodType
:1:
2:
Liens utiles:
Modèle de données d'invocation des descripteurs
Descripteur HowTo Guide d'invocation des descripteurs
Ce que vous cherchez est
setattr
je crois.Utiliser cette fonction pour définir un attribut d'un objet.
A
, pas l'instancea
.setattr(A,'printme',printme)
au lieu de simplementA.printme = printme
?Depuis cette question posée pour les non-versions de Python, voici JavaScript:
La consolidation de Jason Pratt et le wiki de la communauté réponses, avec un oeil sur les résultats de différentes méthodes de reliure:
Remarque surtout comment l'ajout de la fonction de liaison en tant que méthode de classe œuvres, mais le référencement champ d'application est incorrecte.
Personnellement, je préfère l'externe ADDMETHOD fonction de l'itinéraire, car elle me permet d'attribuer dynamiquement des nouveaux noms de méthode à l'intérieur d'un itérateur ainsi.
addmethod
réécrit de la manière suivantedef addmethod(self, method, name): self.__dict__[name] = types.MethodType( method, self )
résout le problèmeC'est en fait un addon pour la réponse de "Jason Pratt"
Bien que Jasons réponse fonctionne, il fonctionne seulement si l'on veut ajouter une fonction à une classe.
Il ne fonctionne pas pour moi quand j'ai essayé de recharger une méthode déjà existante de la .py fichier de code source.
Il m'a fallu pour les âges à trouver une solution de contournement, mais le truc semble simple...
1.st importer le code à partir du fichier de code source
2.nd forcer un rechargement
3.rd types d'utilisation.FunctionType(...) pour convertir l'importés et de la méthode liée à une fonction
vous pouvez également passer sur le courant des variables globales, comme le reloaded méthode serait dans un espace de noms différent
4.th maintenant, vous pouvez continuer comme suggéré par "Jason Pratt"
en utilisant les types.MethodType(...)
Exemple:
Ce que Jason Pratt affiché est correct.
Comme vous pouvez le voir, Python ne pas envisager de b() toute différente de celle d'un(). En Python, toutes les méthodes sont juste des variables qui se trouvent être des fonctions.
Test
, pas une instance.Si elle peut être d'une aide quelconque, j'ai récemment publié une bibliothèque Python nommé Gorille à rendre le processus de monkey patching plus pratique.
À l'aide d'une fonction
needle()
pour patch un module nomméguineapig
va comme suit:Mais il s'occupe aussi de plus intéressant cas d'utilisation comme indiqué dans le FAQ de la la documentation.
Le code est disponible sur GitHub.
Cette question a été ouvert il y a des années, mais bon, il y a un moyen facile de simuler la liaison d'une fonction à une instance de classe à l'aide de décorateurs:
Là, quand vous passez à la fonction et à l'instance pour le classeur décorateur, il va créer une nouvelle fonction, avec le même code objet que le premier. Ensuite, l'instance de la classe est stockée dans un attribut de la fonction nouvellement créée. Le décorateur de retour d'une (troisième) d'appel de fonction automatiquement copiés fonction, en donnant l'exemple en tant que premier paramètre.
En conclusion, vous obtenez une fonction simulant c'est la liaison de l'instance de classe. Laisser la fonction d'origine inchangé.
Je trouve étrange que personne n'a mentionné que toutes les méthodes énumérées ci-dessus crée un cycle de référence entre l'ajout de la méthode et de l'instance, provoquant l'objet persistant jusqu'à la collecte des ordures. Il y avait un vieux truc de l'ajout d'un descripteur par l'extension de la classe de l'objet:
Avec cela, vous pouvez utiliser l'auto pointeur