858 Stimmen

Hinzufügen einer Methode zu einer existierenden Objektinstanz

Ich habe gelesen, dass es in Python möglich ist, eine Methode zu einem bestehenden Objekt (d.h. nicht in der Klassendefinition) hinzuzufügen.

Ich verstehe, dass das nicht immer gut ist. Aber wie könnte man das machen?

7voto

Max Punkte 455

Dies ist eigentlich ein Zusatz zur Antwort von "Jason Pratt".

Obwohl Jasons Antwort funktioniert, funktioniert sie nur, wenn man eine Funktion zu einer Klasse hinzufügen möchte. Bei mir hat es nicht funktioniert, als ich versucht habe, eine bereits vorhandene Methode aus der .py-Quellcodedatei neu zu laden.

Ich habe lange gebraucht, um eine Lösung zu finden, aber der Trick scheint einfach zu sein... 1.st den Code aus der Quellcode-Datei importieren 2.nd ein Neuladen erzwingen 3.rd verwenden Sie types.FunctionType(...), um die importierte und gebundene Methode in eine Funktion umzuwandeln Sie können auch die aktuellen globalen Variablen weitergeben, da die neu geladene Methode in einem anderen Namensraum liegen würde 4. nun können Sie wie von "Jason Pratt" vorgeschlagen fortfahren Verwendung der types.MethodType(...)

Beispiel:

# 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

5voto

lain Punkte 420

Diese Frage wurde schon vor Jahren gestellt, aber hey, es gibt einen einfachen Weg, die Bindung einer Funktion an eine Klasseninstanz mit Hilfe von Dekoratoren zu simulieren:

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

Wenn Sie dort die Funktion und die Instanz an den Binder-Dekorator übergeben, wird dieser eine neue Funktion mit demselben Code-Objekt wie die erste Funktion erstellen. Dann wird die angegebene Instanz der Klasse in einem Attribut der neu erstellten Funktion gespeichert. Der Dekorator gibt eine (dritte) Funktion zurück, die automatisch die kopierte Funktion aufruft, wobei die Instanz als erster Parameter übergeben wird.

Als Ergebnis erhalten Sie eine Funktion, die ihre Bindung an die Klasseninstanz simuliert. Dabei bleibt die ursprüngliche Funktion unverändert.

5voto

Yu Feng Punkte 219

Ich finde es seltsam, dass niemand erwähnt hat, dass alle oben aufgeführten Methoden eine Zyklusreferenz zwischen der hinzugefügten Methode und der Instanz erzeugen, wodurch das Objekt bis zur Garbage Collection persistent bleibt. Es gab einen alten Trick, einen Deskriptor hinzuzufügen, indem man die Klasse des Objekts erweitert:

def addmethod(obj, name, func):
    klass = obj.__class__
    subclass = type(klass.__name__, (klass,), {})
    setattr(subclass, name, func)
    obj.__class__ = subclass

4voto

ChristopherC Punkte 1555

Falls es von Nutzen sein kann, habe ich vor kurzem eine Python-Bibliothek namens Gorilla veröffentlicht, um den Prozess von monkey Parcheando bequemer zu machen.

Verwendung einer Funktion needle() um ein Modul namens guineapig geht wie folgt:

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

Es gibt aber auch interessantere Anwendungsfälle, wie die folgende Abbildung zeigt FAQ von der Dokumentation .

Der Code ist verfügbar unter GitHub .

4voto

from types import MethodType

def method(self):
   print 'hi!'

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

Damit können Sie den Selbstzeiger verwenden

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X