Ajout d'une méthode à une instance d'objet existante

J'ai lu qu'il est possible d'ajouter une méthode à un objet existant (c'est-à-dire, pas dans la définition de classe) en Python.

Je comprends que ce n'est pas toujours bon de le faire. Mais comment pourrait-on faire cela?

0

18 Réponses

Je ne connais pas la syntaxe Python, mais je sais que ruby peut le faire, et c'est plutôt trivial. Disons que vous voulez ajouter une méthode à Array qui imprime la longueur à la sortie standard:

class Array
  def print_length
    puts length
  end
end

Si vous ne voulez pas modifier la classe entière, vous pouvez juste ajouter la méthode à une seule instance du tableau, et aucun autre tableau n'aura la méthode:

array = [1, 2, 3]
def array.print_length
  puts length
end

Juste être conscient des problèmes liés à l'utilisation de cette fonctionnalité. En fait, Jeff Atwood a écrit à ce sujet il n'y a pas si longtemps.

0
ajouté

Ce que vous cherchez est setattr je crois. Utilisez ceci pour définir un attribut sur un objet.

>>> def printme(s): print repr(s)
>>> class A: pass
>>> setattr(A,'printme',printme)
>>> a = A()
>>> a.printme() # s becomes the implicit 'self' variable
< __ main __ . A instance at 0xABCDEFG>
0
ajouté
Y at-il une raison d'utiliser setattr (A, 'printme', printme) au lieu de simplement A.printme = printme ?
ajouté l'auteur Tobias Kienzler, source
Cela corrige la classe A , pas l'instance a .
ajouté l'auteur Ethan Furman, source
Cela a du sens si l'on construit le nom de la méthode au moment de l'exécution.
ajouté l'auteur rr-, source

Ajout d'une méthode à une instance d'objet existante

     

J'ai lu qu'il est possible d'ajouter une méthode à un objet existant (par exemple, pas dans la définition de classe) en Python.

     

Je comprends que ce n'est pas toujours une bonne décision de le faire. Mais comment faire cela?

Oui, c'est possible - Mais pas recommandé

Je ne le recommande pas. C'est une mauvaise idée. Ne fais pas ça.

Voici quelques raisons:

  • Vous allez ajouter un objet lié à chaque occurrence à laquelle vous faites cela. Si vous le faites beaucoup, vous perdrez probablement beaucoup de mémoire. Les méthodes liées ne sont généralement créées que pour la courte durée de leur appel, et elles cessent alors d'exister lorsqu'elles sont collectées automatiquement. Si vous le faites manuellement, vous aurez une liaison de nom référençant la méthode liée - ce qui empêchera sa récupération de place lors de son utilisation.
  • Les instances d'objet d'un type donné ont généralement ses méthodes sur tous les objets de ce type. Si vous ajoutez des méthodes ailleurs, certaines instances auront ces méthodes et d'autres non. Les programmeurs ne s'y attendront pas, et vous risquez de violer la règle de la plus petite surprise .
  • Comme il y a d'autres bonnes raisons de ne pas le faire, vous vous ferez une mauvaise réputation si vous le faites.

Ainsi, je suggère que vous ne fassiez pas ceci à moins que vous ayez une très bonne raison. Il est préférable de définir la méthode correcte dans la définition de la classe ou less de préférence pour corriger directement la classe, comme ceci:

Foo.sample_method = sample_method

Comme c'est instructif, cependant, je vais vous montrer quelques façons de le faire.

Comment cela peut-il être fait

Voici un code d'installation. Nous avons besoin d'une définition de classe. Il pourrait être importé, mais cela n'a pas vraiment d'importance.

class Foo(object):
    '''An empty class to demonstrate adding a method to an instance'''

Créer une instance:

foo = Foo()

Créez une méthode pour l'ajouter:

def sample_method(self, bar, baz):
    print(bar + baz)

Method nought (0) - use the descriptor method, __get__

Les recherches pointées sur les fonctions appellent la méthode __ get __ de la fonction avec l'instance, liant l'objet à la méthode et créant ainsi une "méthode liée".

foo.sample_method = sample_method.__get__(foo)

et maintenant:

>>> foo.sample_method(1,2)
3

Méthode un - types.MethodType

Tout d'abord, importer les types, à partir de laquelle nous aurons le constructeur de la méthode:

import types

Maintenant, nous ajoutons la méthode à l'instance. Pour ce faire, nous avons besoin du constructeur MethodType du module types (que nous avons importé ci-dessus).

La signature d'argument pour types.MethodType est (fonction, instance, classe) :

foo.sample_method = types.MethodType(sample_method, foo, Foo)

et utilisation:

>>> foo.sample_method(1,2)
3

Deuxième méthode: liaison lexicale

Tout d'abord, nous créons une fonction wrapper qui lie la méthode à l'instance:

def bind(instance, method):
    def binding_scope_fn(*args, **kwargs): 
        return method(instance, *args, **kwargs)
    return binding_scope_fn

usage:

>>> foo.sample_method = bind(foo, sample_method)    
>>> foo.sample_method(1,2)
3

Méthode trois: functools.partial

Une fonction partielle applique le (s) premier (s) argument (s) à une fonction (et éventuellement des mots-clés), et peut ensuite être appelée avec les arguments restants (et remplacer les arguments de mot-clé). Ainsi:

>>> from functools import partial
>>> foo.sample_method = partial(sample_method, foo)
>>> foo.sample_method(1,2)
3    

Cela est logique lorsque vous considérez que les méthodes liées sont des fonctions partielles de l'instance.

Fonction non liée en tant qu'attribut d'objet - pourquoi cela ne fonctionne pas:

Si nous essayons d'ajouter la méthode sample_method de la même manière que nous pourrions l'ajouter à la classe, elle n'est pas liée à l'instance et ne prend pas le soi implicite comme premier argument.

>>> foo.sample_method = sample_method
>>> foo.sample_method(1,2)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: sample_method() takes exactly 3 arguments (2 given)

Nous pouvons faire fonctionner la fonction indépendante en passant explicitement l'instance (ou n'importe quoi, puisque cette méthode n'utilise pas réellement la variable d'argument self ), mais elle ne serait pas cohérente avec la signature attendue des autres instances (Si nous corrigeons le singe de cette instance):

>>> foo.sample_method(foo, 1, 2)
3

Conclusion

Vous savez maintenant plusieurs façons de le faire, mais sérieusement, ne le faites pas.

0
ajouté
Mon commentaire était basé sur cette référence: python-reference.readthedocs. io / fr / latest / docs / dunderdsc / & hellip; Ce que je vois maintenant dans les documents officiels, c'est optionnel: docs.python.org/3/howto/descriptor.html#descriptor-protocol
ajouté l'auteur Aidas Bendoraitis, source
La méthode __ get __ a également besoin de la classe en tant que paramètre suivant: sample_method .__ get __ (toto, Foo) .
ajouté l'auteur Aidas Bendoraitis, source
@AidasBendoraitis Je ne dirais pas qu'il "a besoin" de ça, c'est un paramètre facultatif qui est fourni lors de l'application du protocole descripteur - mais les fonctions python n'utilisent pas l'argument: github.com/python/cpython/blob/master/Objects/funcobject.c#L‌ 581
ajouté l'auteur Aaron Hall, source
@Atcold J'ai développé des raisons d'éviter cela dans l'introduction.
ajouté l'auteur Aaron Hall, source
Le Disclaimer est ce que je me demandais. Les définitions de méthodes sont simplement des fonctions imbriquées dans la définition de classe.
ajouté l'auteur Atcold, source

Module new is deprecated since python 2.6 and removed in 3.0, use types

see http://docs.python.org/library/new.html

Dans l'exemple ci-dessous, j'ai délibérément retiré la valeur de retour de la fonction patch_me() . Je pense que donner une valeur de retour peut faire croire que patch renvoie un nouvel objet, ce qui n'est pas vrai - il modifie le nouvel entrant. Probablement cela peut faciliter une utilisation plus disciplinée du monkeypatching.

import types

class A(object):#but seems to work for old style objects too
    pass

def patch_me(target):
    def method(target,x):
        print "x=",x
        print "called from", target
    target.method = types.MethodType(method,target)
    #add more if needed

a = A()
print a
#out: <__main__.A object at 0x2b73ac88bfd0>  
patch_me(a)    #patch instance
a.method(5)
#out: x= 5
#out: called from <__main__.A object at 0x2b73ac88bfd0>
patch_me(A)
A.method(6)        #can patch class too
#out: x= 6
#out: called from 
0
ajouté

Il existe au moins deux façons d'attacher une méthode à une instance sans types.MethodType :

>>> class A:
...  def m(self):
...   print 'im m, invoked with: ', self

>>> a = A()
>>> a.m()
im m, invoked with:  <__main__.A instance at 0x973ec6c>
>>> a.m
<__main__.A instance at 0x973ec6c>>
>>> 
>>> def foo(firstargument):
...  print 'im foo, invoked with: ', firstargument

>>> foo

1:

>>> a.foo = foo.__get__(a, A) # or foo.__get__(a, type(a))
>>> a.foo()
im foo, invoked with:  <__main__.A instance at 0x973ec6c>
>>> a.foo
<__main__.A instance at 0x973ec6c>>

2:

>>> instancemethod = type(A.m)
>>> instancemethod

>>> a.foo2 = instancemethod(foo, a, type(a))
>>> a.foo2()
im foo, invoked with:  <__main__.A instance at 0x973ec6c>
>>> a.foo2
<__main__.A instance at 0x973ec6c>>

Useful links:
Data model - invoking descriptors
Descriptor HowTo Guide - invoking descriptors

0
ajouté

Depuis cette question a demandé des versions non-Python, voici JavaScript:

a.methodname = function() { console.log("Yay, a new method!") }
0
ajouté

Je pense que les réponses ci-dessus ont manqué le point clé.

Ayons une classe avec une méthode:

class A(object):
    def m(self):
        pass

Maintenant, jouons avec ipython:

In [2]: A.m
Out[2]: 

Ok, m() devient en quelque sorte une méthode non liée à A . Mais est-ce vraiment comme ça?

In [5]: A.__dict__['m']
Out[5]: 

Il s'avère que m() est juste une fonction, dont la référence est ajoutée au dictionnaire de classe A - il n'y a pas de magie. Alors pourquoi A.m nous donne une méthode non liée? C'est parce que le point n'est pas traduit en une simple recherche de dictionnaire. C'est de facto un appel de A .__ classe __.__ getattribute __ (A, 'm'):

In [11]: class MetaA(type):
   ....:     def __getattribute__(self, attr_name):
   ....:         print str(self), '-', attr_name

In [12]: class A(object):
   ....:     __metaclass__ = MetaA

In [23]: A.m
 - m
 - m

Maintenant, je ne suis pas sûr de savoir pourquoi la dernière ligne est imprimée deux fois, mais il reste clair ce qui se passe là-bas.

Maintenant, ce que fait par défaut __getattribute__, c'est qu'il vérifie si l'attribut est un soi-disant descripteur ou non, c'est-à-dire s'il implémente une méthode spéciale __get__. S'il implémente cette méthode, alors ce qui est retourné est le résultat de l'appel de cette méthode __get__. Pour en revenir à la première version de notre classe A , voici ce que nous avons:

In [28]: A.__dict__['m'].__get__(None, A)
Out[28]: 

Et parce que les fonctions Python implémentent le protocole descripteur, si elles sont appelées au nom d'un objet, elles se lient à cet objet dans leur méthode __get__.

Ok, comment ajouter une méthode à un objet existant? En supposant que cela ne vous dérange pas de patcher classe, c'est aussi simple que:

B.m = m

Alors B.m "devient" une méthode non liée, grâce à la magie des descripteurs.

Et si vous voulez ajouter une méthode à un seul objet, alors vous devez émuler la machine vous-même, en utilisant types.MethodType:

b.m = types.MethodType(m, b)

Au fait:

In [2]: A.m
Out[2]: 

In [59]: type(A.m)
Out[59]: 

In [60]: type(b.m)
Out[60]: 

In [61]: types.MethodType
Out[61]: 
0
ajouté

Cette question a été ouverte 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 en utilisant des décorateurs:

def binder (function, instance):
  copy_of_function = type (function) (function.func_code, {})
  copy_of_function.__bind_to__ = instance
  def bound_function (*args, **kwargs):
    return copy_of_function (copy_of_function.__bind_to__, *args, **kwargs)
  return bound_function


class SupaClass (object):
  def __init__ (self):
    self.supaAttribute = 42


def new_method (self):
  print self.supaAttribute


supaInstance = SupaClass ()
supaInstance.supMethod = binder (new_method, supaInstance)

otherInstance = SupaClass ()
otherInstance.supaAttribute = 72
otherInstance.supMethod = binder (new_method, otherInstance)

otherInstance.supMethod ()
supaInstance.supMethod ()

There, when you pass the function and the instance to the binder decorator, it will create a new function, with the same code object as the first one. Then, the given instance of the class is stored in an attribute of the newly created function. The decorator return a (third) function calling automatically the copied function, giving the instance as the first parameter.

In conclusion you get a function simulating it's binding to the class instance. Letting the original function unchanged.

0
ajouté

Consolider les réponses de Jason Pratt et de la communauté wiki, en examinant les résultats des différentes méthodes de liaison:

Notez en particulier comment ajouter la fonction de liaison en tant que méthode de classe fonctionne , mais la portée de référencement est incorrecte.

#!/usr/bin/python -u
import types
import inspect

## dynamically adding methods to a unique instance of a class


# get a list of a class's method type attributes
def listattr(c):
    for m in [(n, v) for n, v in inspect.getmembers(c, inspect.ismethod) if isinstance(v,types.MethodType)]:
        print m[0], m[1]

# externally bind a function as a method of an instance of a class
def ADDMETHOD(c, method, name):
    c.__dict__[name] = types.MethodType(method, c)

class C():
    r = 10 # class attribute variable to test bound scope

    def __init__(self):
        pass

    #internally bind a function as a method of self's class -- note that this one has issues!
    def addmethod(self, method, name):
        self.__dict__[name] = types.MethodType( method, self.__class__ )

    # predfined function to compare with
    def f0(self, x):
        print 'f0\tx = %d\tr = %d' % ( x, self.r)

a = C() # created before modified instnace
b = C() # modified instnace


def f1(self, x): # bind internally
    print 'f1\tx = %d\tr = %d' % ( x, self.r )
def f2( self, x): # add to class instance's .__dict__ as method type
    print 'f2\tx = %d\tr = %d' % ( x, self.r )
def f3( self, x): # assign to class as method type
    print 'f3\tx = %d\tr = %d' % ( x, self.r )
def f4( self, x): # add to class instance's .__dict__ using a general function
    print 'f4\tx = %d\tr = %d' % ( x, self.r )


b.addmethod(f1, 'f1')
b.__dict__['f2'] = types.MethodType( f2, b)
b.f3 = types.MethodType( f3, b)
ADDMETHOD(b, f4, 'f4')


b.f0(0) # OUT: f0   x = 0   r = 10
b.f1(1) # OUT: f1   x = 1   r = 10
b.f2(2) # OUT: f2   x = 2   r = 10
b.f3(3) # OUT: f3   x = 3   r = 10
b.f4(4) # OUT: f4   x = 4   r = 10


k = 2
print 'changing b.r from {0} to {1}'.format(b.r, k)
b.r = k
print 'new b.r = {0}'.format(b.r)

b.f0(0) # OUT: f0   x = 0   r = 2
b.f1(1) # OUT: f1   x = 1   r = 10  !!!!!!!!!
b.f2(2) # OUT: f2   x = 2   r = 2
b.f3(3) # OUT: f3   x = 3   r = 2
b.f4(4) # OUT: f4   x = 4   r = 2

c = C() # created after modifying instance

# let's have a look at each instance's method type attributes
print '\nattributes of a:'
listattr(a)
# OUT:
# attributes of a:
# __init__ <__main__.C instance at 0x000000000230FD88>>
# addmethod <__main__.C instance at 0x000000000230FD88>>
# f0 <__main__.C instance at 0x000000000230FD88>>

print '\nattributes of b:'
listattr(b)
# OUT:
# attributes of b:
# __init__ <__main__.C instance at 0x000000000230FE08>>
# addmethod <__main__.C instance at 0x000000000230FE08>>
# f0 <__main__.C instance at 0x000000000230FE08>>
# f1 >
# f2 <__main__.C instance at 0x000000000230FE08>>
# f3 <__main__.C instance at 0x000000000230FE08>>
# f4 <__main__.C instance at 0x000000000230FE08>>

print '\nattributes of c:'
listattr(c)
# OUT:
# attributes of c:
# __init__ <__main__.C instance at 0x0000000002313108>>
# addmethod <__main__.C instance at 0x0000000002313108>>
# f0 <__main__.C instance at 0x0000000002313108>>

Personnellement, je préfère la route de fonction ADDMETHOD externe, car elle me permet également d'attribuer dynamiquement de nouveaux noms de méthodes dans un itérateur.

def y(self, x):
    pass
d = C()
for i in range(1,5):
    ADDMETHOD(d, y, 'f%d' % i)
print '\nattributes of d:'
listattr(d)
# OUT:
# attributes of d:
# __init__ <__main__.C instance at 0x0000000002303508>>
# addmethod <__main__.C instance at 0x0000000002303508>>
# f0 <__main__.C instance at 0x0000000002303508>>
# f1 <__main__.C instance at 0x0000000002303508>>
# f2 <__main__.C instance at 0x0000000002303508>>
# f3 <__main__.C instance at 0x0000000002303508>>
# f4 <__main__.C instance at 0x0000000002303508>>
0
ajouté
addmethod réécrit de la manière suivante def addmethod (self, méthode, nom): self .__ dict __ [nom] = types.MethodType (méthode, self) résout le problème
ajouté l'auteur Antony Hatchkins, source

Dans Python, le patch singe fonctionne généralement en écrasant une signature de classe ou de fonction avec la vôtre. Voici un exemple du Zope Wiki :

from SomeOtherProduct.SomeModule import SomeClass
def speak(self):
   return "ook ook eee eee eee!"
SomeClass.speak = speak

Ce code remplacera / créera une méthode appelée speak sur la classe. Dans le article récent de Jeff Atwood sur la correction de singe . Il montre un exemple en C# 3.0 qui est le langage courant que j'utilise pour le travail.

0
ajouté
Mais cela influence toutes les instances de la classe, pas seulement une.
ajouté l'auteur glglgl, source

En Python, il existe une différence entre les fonctions et les méthodes liées.

>>> def foo():
...     print "foo"
...
>>> class A:
...     def bar( self ):
...         print "bar"
...
>>> a = A()
>>> foo

>>> a.bar
<__main__.A instance at 0x00A9BC88>>
>>>

Les méthodes liées ont été "liées" (comment descriptives) à une instance, et cette instance sera passée comme premier argument à chaque fois que la méthode est appelée.

Les callables qui sont des attributs d'une classe (par opposition à une instance) ne sont toujours pas liés, vous pouvez donc modifier la définition de la classe quand vous le souhaitez:

>>> def fooFighters( self ):
...     print "fooFighters"
...
>>> A.fooFighters = fooFighters
>>> a2 = A()
>>> a2.fooFighters
<__main__.A instance at 0x00A9BEB8>>
>>> a2.fooFighters()
fooFighters

Les instances précédemment définies sont également mises à jour (à condition qu'elles n'aient pas elles-mêmes remplacé l'attribut):

>>> a.fooFighters()
fooFighters

Le problème vient quand vous voulez attacher une méthode à une seule instance:

>>> def barFighters( self ):
...     print "barFighters"
...
>>> a.barFighters = barFighters
>>> a.barFighters()
Traceback (most recent call last):
  File "", line 1, in 
TypeError: barFighters() takes exactly 1 argument (0 given)

La fonction n'est pas automatiquement liée lorsqu'elle est attachée directement à une instance:

>>> a.barFighters

Pour le lier, nous pouvons utiliser la fonction MethodType dans le module types :

>>> import types
>>> a.barFighters = types.MethodType( barFighters, a )
>>> a.barFighters
<__main__.A instance at 0x00A9BC88>>
>>> a.barFighters()
barFighters

Cette fois, les autres instances de la classe n'ont pas été affectées:

>>> a2.barFighters()
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: A instance has no attribute 'barFighters'

Plus d'informations peuvent être trouvées en lisant sur descripteurs et metaclass programmation .

0
ajouté
Les méthodes liées en Python sont-elles similaires aux méthodes d'extensions en C #?
ajouté l'auteur Andy, source
@EndermanAPM: Plusieurs: il est plus susceptible de continuer à fonctionner exactement de la même manière que l'accès à l'attribut sur une instance. Cela fonctionnera aussi pour classmethod et staticmethod et d'autres descripteurs. Cela évite d'encombrer l'espace de noms avec encore une autre importation.
ajouté l'auteur Martijn Pieters, source
Le code complet de l'approche du descripteur suggérée est a.barFighters = barFighters .__ get __ (a)
ajouté l'auteur eqzx, source
@MartijnPieters avantages de l'utilisation du descripteur protocole vs la création d'un MethodType de côté peut-être un peu plus lisible.
ajouté l'auteur EndermanAPM, source

Ce que Jason Pratt a posté est correct.

>>> class Test(object):
...   def a(self):
...     pass
... 
>>> def b(self):
...   pass
... 
>>> Test.b = b
>>> type(b)

>>> type(Test.a)

>>> type(Test.b)

Comme vous pouvez le voir, Python ne considère pas b() comme différent de (). En Python, toutes les méthodes ne sont que des variables qui sont des fonctions.

0
ajouté
Vous patchez la classe Test , pas une instance de celui-ci.
ajouté l'auteur Ethan Furman, source

Vous devriez vraiment regarder fruit défendu , c'est une bibliothèque de python qui fournit le support au patch de singe N'IMPORTE QUELLE classe de python, même des cordes.

0
ajouté
Généralement, les liens vers un outil ou une bibliothèque doivent être accompagnés de notes d'utilisation ou d'un exemple de code , ou si possible les deux. Cependant, cela répond au moins à la norme minimale dans le message lié en incluant une explication spécifique de la façon dont la ressource liée est applicable au problème.
ajouté l'auteur Nathan Tuggy, source

Si cela peut être utile, j'ai récemment sorti une bibliothèque Python nommée Gorilla pour rendre le processus de correction de singe plus pratique.

Utiliser une fonction needle() pour patcher un module nommé guineapig va comme suit:

import gorilla
import guineapig
@gorilla.patch(guineapig)
def needle():
    print("awesome")

Mais il prend également en charge des cas d'utilisation plus intéressants, comme indiqué dans le FAQ du documentation .

Le code est disponible sur GitHub .

0
ajouté

Vous pouvez utiliser lambda pour lier une méthode à une instance:

def run(self):
    print self._instanceString

class A(object):
    def __init__(self):
        self._instanceString = "C'est une chaîne d'instance"

a = A()
a.run = lambda: run(a)
a.run()

C'est une chaîne d'instance

Processus terminé avec le code de sortie 0

0
ajouté

Ceci est en fait un addon à la réponse de "Jason Pratt"

Bien que Jasons réponde aux travaux, cela ne fonctionne que si l'on veut ajouter une fonction à une classe. Cela n'a pas fonctionné pour moi lorsque j'ai essayé de recharger une méthode déjà existante à partir du fichier de code source .py.

Il m'a fallu des années pour trouver une solution de contournement, mais l'astuce semble simple ... 1.st importer le code du fichier de code source 2.nd forcer une recharge 3.rd utilise types.FunctionType (...) pour convertir la méthode importée et liée en une fonction vous pouvez également transmettre les variables globales actuelles, car la méthode reloaded se trouverait dans un espace de noms différent 4. Maintenant vous pouvez continuer comme suggéré par "Jason Pratt"   en utilisant les types.MethodType (...)

Exemple:

# this class resides inside ReloadCodeDemo.py
class A:
    def bar( self ):
        print "bar1"

    def reloadCode(self, methodName):
        ''' use this function to reload any function of class A'''
        import types
        import ReloadCodeDemo as ReloadMod # import the code as module
        reload (ReloadMod) # force a reload of the module
        myM = getattr(ReloadMod.A,methodName) #get reloaded Method
        myTempFunc = types.FunctionType(# convert the method to a simple function
                                myM.im_func.func_code, #the methods code
                                globals(), # globals to use
                                argdefs=myM.im_func.func_defaults # default values for variables if any
                                ) 
        myNewM = types.MethodType(myTempFunc,self,self.__class__) #convert the function to a method
        setattr(self,methodName,myNewM) # add the method to the function

if __name__ == '__main__':
    a = A()
    a.bar()
    # now change your code and save the file
    a.reloadCode('bar') # reloads the file
    a.bar() # now executes the reloaded code
0
ajouté

Je trouve étrange que personne n'ait mentionné que toutes les méthodes listées ci-dessus créent une référence de cycle entre la méthode ajoutée et l'instance, provoquant la persistance de l'objet jusqu'à la récupération de place. Il y avait une vieille astuce ajoutant un descripteur en étendant la classe de l'objet:

def addmethod(obj, name, func):
    klass = obj.__class__
    subclass = type(klass.__name__, (klass,), {})
    setattr(subclass, name, func)
    obj.__class__ = subclass
0
ajouté
from types import MethodType

def method(self):
   print 'hi!'


setattr( targetObj, method.__name__, MethodType(method, targetObj, type(method)) )

Avec cela, vous pouvez utiliser le pointeur automatique

0
ajouté