Hinzufügen einer Methode auf ein vorhandenes Objekt Instance

stimmen
488

Ich habe gelesen, dass es möglich ist, ein Verfahren zu einem vorhandenen Objekt (dh nicht in der Klassendefinition) in Python hinzuzufügen.

Ich verstehe, dass es nicht immer gut ist, dies zu tun. Aber wie könnte man dies tun?

Veröffentlicht am 04/08/2008 um 03:17
quelle vom benutzer
In anderen Sprachen...                            


18 antworten

stimmen
736

In Python gibt es einen Unterschied zwischen den Funktionen und gebundenen Methoden.

>>> def foo():
...     print "foo"
...
>>> class A:
...     def bar( self ):
...         print "bar"
...
>>> a = A()
>>> foo
<function foo at 0x00A98D70>
>>> a.bar
<bound method A.bar of <__main__.A instance at 0x00A9BC88>>
>>>

Gebundene Methoden wurden „gebunden“ (wie beschreibende) auf eine Instanz, und das Beispiel wird als erstes Argument übergeben werden, wenn die Methode aufgerufen wird.

Callables, die Attribute einer Klasse sind (im Gegensatz zu einer Instanz entgegengesetzt) ​​sind noch nicht gebundene, obwohl, so dass Sie die Klassendefinition ändern können, wann immer Sie wollen:

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

Vorher definierten Fällen auch (solange sie das Attribut selbst nicht außer Kraft gesetzt haben) aktualisiert:

>>> a.fooFighters()
fooFighters

Das Problem kommt, wenn Sie eine Methode zu einer einzigen Instanz anhängen möchten:

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

Die Funktion wird nicht automatisch gebunden, wenn es direkt an eine Instanz gebunden ist:

>>> a.barFighters
<function barFighters at 0x00A98EF0>

So binden Sie es, können wir die Verwendung Method Funktion im Modul - Typen :

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

Diesmal andere Instanzen der Klasse sind davon nicht betroffen:

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

Weitere Informationen können durch das Lesen über finden Deskriptoren und Metaklasse Programmierung .

Beantwortet am 06/08/2008 um 01:33
quelle vom benutzer

stimmen
80

Modul neu ist seit Python 2.6 als veraltet und in 3.0, Verwendung entfernt Typen

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

Im Beispiel unten habe ich bewusst Rückgabewert entfernt patch_me()Funktion. Ich denke , dass Rückgabewert geben kann man das Patch glauben machen , ein neues Objekt zurückgibt, was nicht wahr ist - es ändert die eingehenden ein. Wahrscheinlich kann dies eine disziplinierte Nutzung von monkeypatching erleichtern.

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 <class '__main__.A'>
Beantwortet am 06/06/2009 um 06:31
quelle vom benutzer

stimmen
47

Hinzufügen einer Methode auf ein vorhandenes Objekt Instance

Ich habe gelesen, dass es möglich ist, ein Verfahren zu einem bestehenden Objekt (zB nicht in der Klassendefinition) in Python hinzuzufügen.

Ich verstehe , dass es nicht immer eine gute Entscheidung ist , dies zu tun. Aber wie könnte man dies tun?

Ja, es ist möglich - aber nicht zu empfehlen

Ich glaube nicht, dies empfehlen. Dies ist eine schlechte Idee. Tun Sie es nicht.

Hier ein paar Gründe:

  • Sie werden ein gebundenes Objekt zu jedem Fall fügen Sie tun dies. Wenn Sie diese viel zu tun, werden Sie wahrscheinlich eine Menge Speicher verschwenden. Gebundene Methoden sind in der Regel nur für die kurze Dauer ihres Anruf erstellt, und sie dann aufhören zu existieren, wenn automatisch Müll gesammelt. Wenn Sie dies manuell tun, werden Sie einen Namen haben die gebundene Methode Bindung Referenzierung - die seine Garbage Collection auf Nutzung zu verhindern.
  • Objektinstanzen eines bestimmten Typs haben in der Regel ihre Methoden auf alle Objekte dieses Typs. Wenn Sie Methoden an anderer Stelle hinzufügen, haben einige Fälle , diese Methoden und andere nicht. Programmierer wird nicht erwartet, und laufen Sie Gefahr , die Verletzung der Regel von mindestens Überraschung .
  • Da es andere wirklich gute Gründe, dies nicht zu tun, geb dir zusätzlich selbst einen schlechten Ruf, wenn Sie es tun.

Daher schlage ich vor, dass Sie dies nicht tun , wenn Sie einen wirklich guten Grund haben. Es ist viel besser , die richtige Methode in der Klassendefinition zu definieren oder weniger bevorzugt Affen-Patch die Klasse direkt, wie folgt aus :

Foo.sample_method = sample_method

Da es lehrreich ist, aber werde ich Ihnen einige Möglichkeiten, dies zu tun zeigen.

Wie es kann getan werden

Hier einige Setup-Code. Wir brauchen eine Klassendefinition. Es könnte eingeführt werden, aber es spielt keine Rolle, wirklich.

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

Erstellen Sie eine Instanz:

foo = Foo()

Erstellen Sie eine Methode, um es hinzuzufügen:

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

Verfahren nichts (0) - verwenden, um das Deskriptor-Verfahren, __get__

Gepunktete Lookups auf Funktionen aufrufen , die __get__Methode der Funktion mit der Instanz, um das Objekt zu dem Verfahren die Bindung und damit die Schaffung eines „bound - Verfahren.“

foo.sample_method = sample_method.__get__(foo)

und nun:

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

Verfahren one - types.MethodType

Zuerst Importtypen, aus denen wir die Methode Konstruktor erhalten:

import types

Nun fügen wir die Methode auf die Instanz. Dazu benötigen wir die Method Konstruktor aus dem typesModul (die wir oben importiert).

Das Argument Signatur für types.MethodType ist (function, instance, class):

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

und Nutzung:

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

Verfahren Zwei: lexikalische Bindung

Zuerst erstellen wir eine Wrapper-Funktion, die das Verfahren zum Beispiel bindet:

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

Verwendung:

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

drei Verfahren: functools.partial

Eine Teilfunktion gilt das erste Argument (e) auf eine Funktion (und optional Schlüsselwort Argumente), und später kann mit den verbleibenden Argumenten (übergeordneten Schlüsselwort und Argumenten) aufgerufen werden. So:

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

Dies macht Sinn, wenn man bedenkt, dass gebundene Methoden Teilfunktionen der Instanz sind.

Ungebundene Funktion als Objekt Attribut - warum dies nicht funktioniert:

Wenn wir versuchen, die sample_method in der gleichen Weise, wie wir es in die Klasse hinzufügen könnten, ist es von der Instanz ungebunden, und ersetzt nicht die implizite Selbst als erstes Argument.

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

Wir können die ungebundene Funktion verwenden können , indem die Instanz explizit vorbei (oder irgendetwas, da diese Methode tatsächlich nicht das Verwendung selfArgument Variable), aber es wäre nicht mit der erwarteten Signatur von anderen Fällen konsistent sein (wenn wir Affen-Patching sind diese Instanz):

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

Fazit

Sie wissen nun mehrere Möglichkeiten , wie Sie können dies tun, aber im Ernst - dies nicht tun.

Beantwortet am 21/01/2015 um 05:31
quelle vom benutzer

stimmen
30

Ich denke, dass die oben genannten Antworten den entscheidenden Punkt verpaßt.

Lassen Sie sich eine Klasse mit einer Methode hat:

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

Nun wollen wir mit ihm in ipython spielen:

In [2]: A.m
Out[2]: <unbound method A.m>

Ok, so m () wird irgendwie ein ungebundenes Methode A . Aber ist es wirklich so?

In [5]: A.__dict__['m']
Out[5]: <function m at 0xa66b8b4>

Es stellt sich heraus , dass m () ist nur eine Funktion, deren Nutzung zu hinzugefügt wird , A - Klasse - Wörterbuch - es gibt keine Magie. Warum Am gibt uns eine ungebundene Methode? Es ist , weil der Punkt nicht auf ein einfaches Nachschlagen im Wörterbuch übersetzt. Es ist de facto ein Anruf von A .__ Klasse __.__ 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
<class '__main__.A'> - m
<class '__main__.A'> - m

Nun, ich bin aus der Spitze von meinem Kopf nicht sicher, warum die letzte Zeile zweimal gedruckt wird, aber noch ist es klar, was dort vor sich geht.

Nun, was der Standard - __getattribute__ tut , ist , dass es überprüft , ob das Attribut ein sogenanntes Descriptor oder nicht, das heißt , wenn es eine spezielle __get__ Methode implementiert. Wenn es diese Methode implementiert, was dann zurückgegeben wird , ist das Ergebnis , dass __get__ Methode aufrufen. Zurück in die erste Version unserer gehen A - Klasse, ist es das , was wir haben:

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

Und weil Python Funktionen des Descriptor-Protokoll implementieren, wenn sie im Namen eines Objekts genannt werden, binden sie sich auf dieses Objekt in ihrer __get__ Methode.

Ok, so wie ein Verfahren zu einem bestehenden Objekt hinzufügen? Angenommen, Sie haben nichts dagegen Patchen Klasse, es ist so einfach wie:

B.m = m

Dann Bm „wird“ ein ungebundenes Methode, dank der Descriptor Magie.

Und wenn Sie eine Methode nur auf ein einzelnes Objekt hinzufügen möchten, dann haben Sie die Maschinen selbst zu emulieren, durch types.MethodType mit:

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

Apropos:

In [2]: A.m
Out[2]: <unbound method A.m>

In [59]: type(A.m)
Out[59]: <type 'instancemethod'>

In [60]: type(b.m)
Out[60]: <type 'instancemethod'>

In [61]: types.MethodType
Out[61]: <type 'instancemethod'>
Beantwortet am 22/01/2012 um 15:20
quelle vom benutzer

stimmen
16

In Python Affe Patchen funktioniert in der Regel durch eine Klasse oder Funktionen Signatur mit Ihrem eigenen überschrieben werden . Unten ist ein Beispiel aus dem Zope Wiki :

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

Dieser Code wird überschreiben / erstellen eine Methode namens auf die Klasse sprechen. In Jeff Atwood kürzlich erschienenen Beitrag auf Affen Patchen . Er zeigt ein Beispiel in C # 3.0 , die die aktuelle Sprache , die ich für die Arbeit verwenden ist.

Beantwortet am 04/08/2008 um 03:31
quelle vom benutzer

stimmen
9

Es gibt mindestens zwei Möglichkeiten , um ein Verfahren zu einer Instanz anhängen ohne 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
<bound method A.m of <__main__.A instance at 0x973ec6c>>
>>> 
>>> def foo(firstargument):
...  print 'im foo, invoked with: ', firstargument

>>> foo
<function foo at 0x978548c>

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
<bound method A.foo of <__main__.A instance at 0x973ec6c>>

2:

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

Nützliche Links:
Datenmodell - Deskriptoren Aufruf
Descriptor HowTo Guide - Aufruf Deskriptoren

Beantwortet am 26/04/2013 um 16:47
quelle vom benutzer

stimmen
7

Sie können Lambda verwenden, um ein Verfahren zu einer Instanz zu binden:

def run(self):
    print self._instanceString

class A(object):
    def __init__(self):
        self._instanceString = "This is instance string"

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

Dies ist beispielsweise Zeichenfolge

Prozess mit Beendigungscode beendet 0

Beantwortet am 21/07/2014 um 13:55
quelle vom benutzer

stimmen
6

Da diese Frage für nicht-Python-Versionen gefragt, hier ist JavaScript:

a.methodname = function () { console.log("Yay, a new method!") }
Beantwortet am 09/03/2012 um 16:07
quelle vom benutzer

stimmen
6

Was Sie suchen ist , setattrglaube ich. Verwenden Sie diese ein Attribut für ein Objekt einzustellen.

>>> 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>
Beantwortet am 07/08/2008 um 12:30
quelle vom benutzer

stimmen
5

Dies ist eigentlich ein Addon auf die Antwort von „Jason Pratt“

Obwohl Jasons Arbeiten beantworten, funktioniert es nur, wenn man eine Funktion zu einer Klasse hinzufügen möchte. Es dauerte nicht für mich arbeiten, wenn ich ein bereits bestehenden Verfahren aus der Py Quellcodedatei neu zu laden versucht.

Es hat mich seit Ewigkeiten eine Abhilfe zu finden, aber der Trick scheint einfach ... 1.st den Code aus dem Quellcode-Datei importieren 2.ten einen Reload 3.rd Verwendung types.FunctionType Gewalt (...) die konvertieren importiert und gebundene Methode auf eine Funktion, die Sie können auch auf den aktuellen globalen Variablen übergeben, da die neu geladen Methode in einem anderen Namespace 4.th wäre jetzt können Sie durch „Jason Pratt“ mit dem types.MethodType wie vorgeschlagen fortsetzen (... )

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
Beantwortet am 18/08/2015 um 15:32
quelle vom benutzer

stimmen
5

Ihr seid wirklich sehen sollten verbotene Frucht , es ist eine Python - Bibliothek , die Unterstützung für Affen, auch Strings Patchen jeder beliebige Python - Klasse bietet.

Beantwortet am 25/08/2013 um 22:56
quelle vom benutzer

stimmen
5

Konsolidieren von Jason Pratt und die Community Wiki Antworten, mit einem Blick auf die Ergebnisse der verschiedenen Methoden der Bindung:

Besonders beachten , wie das Hinzufügen der Bindungsfunktion als eine Klassenmethode funktioniert , aber die Referenzierung Umfang ist falsch.

#!/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__ <bound method C.__init__ of <__main__.C instance at 0x000000000230FD88>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x000000000230FD88>>
# f0 <bound method C.f0 of <__main__.C instance at 0x000000000230FD88>>

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

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

Persönlich bevorzuge ich die externe ADDMETHOD Funktion Route, wie es mir erlaubt, dynamisch neue Methode Namen zuweisen als auch innerhalb eines Iterators.

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__ <bound method C.__init__ of <__main__.C instance at 0x0000000002303508>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x0000000002303508>>
# f0 <bound method C.f0 of <__main__.C instance at 0x0000000002303508>>
# f1 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
# f2 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
# f3 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
# f4 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
Beantwortet am 28/01/2012 um 01:12
quelle vom benutzer

stimmen
4

Was Jason Pratt geschrieben ist richtig.

>>> class Test(object):
...   def a(self):
...     pass
... 
>>> def b(self):
...   pass
... 
>>> Test.b = b
>>> type(b)
<type 'function'>
>>> type(Test.a)
<type 'instancemethod'>
>>> type(Test.b)
<type 'instancemethod'>

Wie Sie sehen können, ist nicht der Auffassung Python nicht b () anders als ein (). In Python sind alle Methoden nur Variablen, die Funktionen zu passieren.

Beantwortet am 22/08/2008 um 15:40
quelle vom benutzer

stimmen
3

Wenn es eine Hilfe sein kann, habe ich vor kurzem eine Python-Bibliothek namens Gorilla zu machen, den Prozess der Affe Patchen bequemer freigegeben.

Mit Hilfe einer Funktion needle()ein Modul Patch namens guineapiggeht wie folgt vor :

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

Aber es kümmert sich auch um interessanter Anwendungsfälle wie in der gezeigten FAQ von der Dokumentation .

Der Code ist auf verfügbar GitHub .

Beantwortet am 15/07/2014 um 03:12
quelle vom benutzer

stimmen
2

Ich finde es seltsam, dass niemand erwähnt, dass alle der oben genannten Methoden einen Zyklus Bezug zwischen dem zusätzlichen Verfahren und der Instanz erzeugt, so dass das Objekt bis Garbage Collection persistent. Es war ein alter Trick eines Descriptor Hinzufügen von der Klasse des Objekts erstreckt:

def addmethod(obj, name, func):
    klass = obj.__class__
    subclass = type(klass.__name__, (klass,), {})
    setattr(subclass, name, func)
    obj.__class__ = subclass
Beantwortet am 30/04/2017 um 04:57
quelle vom benutzer

stimmen
2

Diese Frage wurde vor geöffnet Jahren, aber hey, es ist eine einfache Möglichkeit, die Bindung einer Funktion zu einer Klasseninstanz zu simulieren Dekorateure mit:

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

Dort, wenn Sie die Funktion und die Instanz auf den Bindemittel Dekorateur passieren, wird es eine neue Funktion, mit dem gleichen Codeobjekt wie die ersten erstellen. Dann wird die gegebene Instanz der Klasse in einem Attribute der neu geschaffenen Funktion gespeichert. Der Dekorateur Rück eine (dritte) Funktion automatisch die kopierte Funktion aufrufen, die Instanz als ersten Parameter geben.

Abschließend erhalten Sie eine Funktion es ist die Bindung an die Klasseninstanz zu simulieren. Lassen die ursprüngliche Funktion unverändert.

Beantwortet am 21/12/2015 um 21:39
quelle vom benutzer

stimmen
1
from types import MethodType

def method(self):
   print 'hi!'


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

Damit können Sie den Selbst Zeiger verwenden

Beantwortet am 27/07/2017 um 04:21
quelle vom benutzer

stimmen
-8

Ich weiß nicht, Python-Syntax, aber ich weiß, Rubin kann es tun, und es ist ziemlich trivial. Angenommen, Sie haben ein Verfahren zum Array hinzufügen möchten, dass die Länge an die Standardausgabe druckt:

class Array
  def print_length
    puts length
  end
end

Wenn Sie nicht die ganze Klasse ändern möchten, können Sie einfach die Methode zu einer einzigen Instanz des Arrays hinzufügen und keine anderen Arrays wird das Verfahren haben:

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

Just bewusst sein , der sich mit dieser Funktion verbundenen Fragen. Jeff Atwood tatsächlich schrieb darüber nicht allzu lange her.

Beantwortet am 04/08/2008 um 03:36
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more