Agregar un método a una instancia de objeto existente

643

He leído que es posible agregar un método a un objeto existente (es decir, no en la definición de clase) en Python.

Entiendo que no siempre es bueno hacerlo. Pero, ¿cómo podría uno hacer esto?

akdom
fuente

Respuestas:

921

En Python, hay una diferencia entre funciones y métodos enlazados.

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

Los métodos enlazados se han "enlazado" (cuán descriptivo) a una instancia, y esa instancia se pasará como primer argumento cada vez que se llame al método.

Sin embargo, las llamadas que son atributos de una clase (a diferencia de una instancia) aún no están vinculadas, por lo que puede modificar la definición de la clase cuando lo desee:

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

Las instancias previamente definidas también se actualizan (siempre que no hayan anulado el atributo):

>>> a.fooFighters()
fooFighters

El problema surge cuando desea adjuntar un método a una sola instancia:

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

La función no se vincula automáticamente cuando se adjunta directamente a una instancia:

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

Para vincularlo, podemos usar la función MethodType en el módulo de tipos :

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

Esta vez, otras instancias de la clase no se han visto afectadas:

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

Puede encontrar más información leyendo descriptores y programación de metaclases .

Jason Pratt
fuente
65
En lugar de crear manualmente un MethodType, invoque el protocolo descriptor manualmente y haga que la función produzca su instancia: barFighters.__get__(a)produce un método barFightersenlazado para enlazado a.
Martijn Pieters
2
@MartijnPieters cualquier ventaja de usar el descriptor protocolvs creando un MethodTypelado de quizás ser un poco más legible.
EndermanAPM
17
@EndermanAPM: Varios: es más probable que continúe funcionando exactamente igual que lo que hace el acceso al atributo en una instancia. Se va a trabajar para classmethody staticmethody otros descriptores también. Evita abarrotar el espacio de nombres con otra importación más.
Martijn Pieters
34
El código completo para el enfoque del descriptor sugerido esa.barFighters = barFighters.__get__(a)
eqzx
98

Módulo nuevo en desuso desde python 2.6 y eliminado en 3.0, use tipos

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

En el siguiente ejemplo, he eliminado deliberadamente el valor de retorno de la patch_me()función. Creo que dar un valor de retorno puede hacernos creer que el parche devuelve un nuevo objeto, lo cual no es cierto: modifica el entrante. Probablemente esto pueda facilitar un uso más disciplinado de parches de mono.

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'>
Evgeny
fuente
1
¿Cómo funcionaría esto si el método que se agrega necesita referirse a uno mismo? Mi primer intento conduce a un error de sintaxis, pero agregar self en la definición del método no parece funcionar. tipos de importación clase A (objeto): # pero parece funcionar también para objetos de estilo antiguo ax = 'ax' pass def patch_me (target): método def (target, x): print (self.ax) print ("x =" , x) print ("llamado desde", target) target.method = types.MethodType (method, target) # agregue más si es necesario a = A () print (a.ax)
WesR
85

Prefacio - una nota sobre compatibilidad: otras respuestas solo pueden funcionar en Python 2 - esta respuesta debería funcionar perfectamente en Python 2 y 3. Si solo escribe Python 3, puede dejar de lado explícitamente la herencia object, pero de lo contrario el código debería permanecer igual .

Agregar un método a una instancia de objeto existente

He leído que es posible agregar un método a un objeto existente (por ejemplo, no en la definición de clase) en Python.

Entiendo que no siempre es una buena decisión hacerlo. Pero, ¿cómo podría uno hacer esto?

Sí, es posible, pero no recomendado

No recomiendo esto Esta es una mala idea. No lo hagas

Aquí hay un par de razones:

  • Agregará un objeto vinculado a cada instancia a la que haga esto. Si haces esto mucho, probablemente perderás mucha memoria. Los métodos vinculados generalmente solo se crean por la corta duración de su llamada, y luego dejan de existir cuando se recolecta basura de forma automática. Si hace esto manualmente, tendrá un enlace de nombre que hace referencia al método enlazado, lo que evitará su recolección de basura en el uso.
  • Las instancias de objeto de un tipo dado generalmente tienen sus métodos en todos los objetos de ese tipo. Si agrega métodos en otro lugar, algunas instancias tendrán esos métodos y otras no. Los programadores no esperarán esto, y corre el riesgo de violar la regla de la menor sorpresa .
  • Dado que hay otras buenas razones para no hacerlo, también te darás una mala reputación si lo haces.

Por lo tanto, le sugiero que no haga esto a menos que tenga una buena razón. Es mucho mejor definir el método correcto en la definición de la clase o menos preferiblemente parchear la clase directamente, de esta manera:

Foo.sample_method = sample_method

Sin embargo, dado que es instructivo, te mostraré algunas formas de hacerlo.

Cómo se puede hacer

Aquí hay un código de configuración. Necesitamos una definición de clase. Podría importarse, pero realmente no importa.

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

Crea una instancia:

foo = Foo()

Cree un método para agregarle:

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

Método cero (0): utilice el método del descriptor, __get__

Las búsquedas punteadas en funciones llaman al __get__método de la función con la instancia, vinculando el objeto al método y creando así un "método vinculado".

foo.sample_method = sample_method.__get__(foo)

y ahora:

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

Método uno - tipos.MetodoTipo

Primero, importe los tipos, de los cuales obtendremos el constructor del método:

import types

Ahora agregamos el método a la instancia. Para hacer esto, requerimos el constructor MethodType del typesmódulo (que importamos anteriormente).

La firma del argumento para types.MethodType es (function, instance, class):

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

y uso:

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

Método dos: unión léxica

Primero, creamos una función de contenedor que une el método a la instancia:

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

uso:

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

Método tres: functools.partial

Una función parcial aplica el (los) primer (s) argumento (s) a una función (y opcionalmente argumentos de palabras clave), y luego se puede invocar con los argumentos restantes (y anulando los argumentos de palabras clave). Así:

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

Esto tiene sentido cuando considera que los métodos enlazados son funciones parciales de la instancia.

Función independiente como atributo de objeto: por qué esto no funciona:

Si intentamos agregar sample_method de la misma manera que podríamos agregarlo a la clase, no está vinculado a la instancia y no toma el self implícito como primer argumento.

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

Podemos hacer que la función independiente funcione explícitamente pasando la instancia (o cualquier cosa, ya que este método en realidad no usa la selfvariable de argumento), pero no sería coherente con la firma esperada de otras instancias (si estamos parcheando mono) esta instancia):

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

Conclusión

Ahora ya sabe varias formas en las que se podía hacer esto, pero con toda seriedad - no lo hace.

Aaron Hall
fuente
1
El descargo de responsabilidad es lo que me preguntaba. La definición de métodos son simplemente funciones anidadas dentro de la definición de clase.
Atcold
1
@ Attold He ampliado las razones para evitar hacer esto en la introducción.
Aaron Hall
El __get__método también necesita la clase que el siguiente parámetro: sample_method.__get__(foo, Foo).
Aidas Bendoraitis
2
@AidasBendoraitis No diría que lo "necesita", es un parámetro opcional que se proporciona al aplicar el protocolo descriptor, pero las funciones de Python no usan el argumento: github.com/python/cpython/blob/master/Objects/funcobject .c # L581
Aaron Hall
Mi comentario se basó en esta referencia: python-reference.readthedocs.io/en/latest/docs/dunderdsc/… Lo que ahora veo de los documentos oficiales, es opcional: docs.python.org/3/howto/descriptor.html# protocolo descriptor
Aidas Bendoraitis 01 de
35

Creo que las respuestas anteriores perdieron el punto clave.

Tengamos una clase con un método:

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

Ahora, juguemos con él en ipython:

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

Ok, por lo que m () de alguna manera se convierte en un método no unido de A . ¿Pero es realmente así?

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

Resulta que m () es solo una función, referencia a la cual se agrega al diccionario de clase A : no hay magia. Entonces, ¿ por qué Am nos da un método independiente? Es porque el punto no se traduce a una simple búsqueda en el diccionario. Es de facto una llamada de A .__ clase __.__ 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

Ahora, no estoy seguro de por qué la última línea se imprime dos veces, pero aún está claro lo que está sucediendo allí.

Ahora, lo que hace el __getattribute__ predeterminado es verificar si el atributo es un llamado descriptor o no, es decir, si implementa un método __get__ especial. Si implementa ese método, lo que se devuelve es el resultado de llamar a ese método __get__. Volviendo a la primera versión de nuestra clase A , esto es lo que tenemos:

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

Y debido a que las funciones de Python implementan el protocolo descriptor, si se llaman en nombre de un objeto, se unen a ese objeto en su método __get__.

Ok, entonces, ¿cómo agregar un método a un objeto existente? Asumiendo que no te importa parchear la clase, es tan simple como:

B.m = m

Entonces Bm "se convierte" en un método independiente, gracias a la magia del descriptor.

Y si desea agregar un método solo a un solo objeto, entonces debe emular la maquinaria usted mismo, mediante el uso de types.MethodType:

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

Por cierto:

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'>
Tomasz Zieliński
fuente
20

En Python, el parcheo de mono generalmente funciona sobrescribiendo una firma de clase o funciones con la suya. A continuación se muestra un ejemplo de Zope Wiki :

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

Ese código sobrescribirá / creará un método llamado speak en la clase. En la reciente publicación de Jeff Atwood sobre parches de monos . Muestra un ejemplo en C # 3.0, que es el lenguaje actual que uso para el trabajo.

John Downey
fuente
66
Pero influye en todas las instancias de la clase, no solo en una.
glglgl
14

Puede usar lambda para vincular un método a una instancia:

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

Salida:

This is instance string
Evgeny Prokurat
fuente
9

Hay al menos dos formas de adjuntar un método a una instancia sin 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>>

Enlaces útiles:
Modelo de datos: invocación de descriptores Guía descriptiva de
procedimientos: invocación de descriptores

ndpu
fuente
7

Lo que estás buscando es setattr, creo. Use esto para establecer un atributo en un objeto.

>>> 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>
HS.
fuente
8
Esto es parchear la clase A, no la instancia a.
Ethan Furman
55
¿Hay alguna razón para usar en setattr(A,'printme',printme)lugar de simplemente A.printme = printme?
Tobias Kienzler
1
Tiene sentido si uno construye el nombre del método en tiempo de ejecución.
rr-
6

Como esta pregunta solicitaba versiones que no fueran de Python, aquí está JavaScript:

a.methodname = function () { console.log("Yay, a new method!") }
Tamzin Blake
fuente
5

Consolidando las respuestas del wiki de Jason Pratt y de la comunidad, con un vistazo a los resultados de diferentes métodos de enlace:

Especialmente en cuenta cómo la adición de la función de unión como un método de clase de obras , pero el alcance referencia es incorrecta.

#!/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>>

Personalmente, prefiero la ruta externa de la función ADDMETHOD, ya que me permite asignar dinámicamente nuevos nombres de métodos dentro de un iterador también.

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>>
Nisan.H
fuente
addmethodreescrito de la siguiente manera def addmethod(self, method, name): self.__dict__[name] = types.MethodType( method, self )resuelve el problema
Antony Hatchkins
5

Esto es realmente un complemento de la respuesta de "Jason Pratt"

Aunque la respuesta de Jasons funciona, solo funciona si uno quiere agregar una función a una clase. No funcionó para mí cuando intenté volver a cargar un método ya existente desde el archivo de código fuente .py.

Me llevó mucho tiempo encontrar una solución, pero el truco parece simple ... 1. importar el código del archivo de código fuente 2. y forzar una recarga 3. 3. usar tipos. FunctionType (...) para convertir el código el método importado y vinculado a una función también puede pasar las variables globales actuales, ya que el método recargado estaría en un espacio de nombres diferente 4. Ahora puede continuar como lo sugiere "Jason Pratt" usando los tipos. Método (... )

Ejemplo:

# 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
Max
fuente
3

Si puede ser de alguna ayuda, recientemente lancé una biblioteca de Python llamada Gorilla para hacer que el proceso de parchear mono sea más conveniente.

El uso de una función needle()para parchear un módulo llamado guineapiges el siguiente:

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

Pero también se ocupa de casos de uso más interesantes como se muestra en las preguntas frecuentes de la documentación .

El código está disponible en GitHub .

ChristopherC
fuente
3

Esta pregunta se abrió hace años, pero bueno, hay una manera fácil de simular el enlace de una función a una instancia de clase usando decoradores:

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

Allí, cuando pase la función y la instancia al decorador de carpetas, creará una nueva función, con el mismo objeto de código que la primera. Luego, la instancia dada de la clase se almacena en un atributo de la función recién creada. El decorador devuelve una (tercera) función que llama automáticamente a la función copiada, dando la instancia como primer parámetro.

En conclusión, obtienes una función que simula que está vinculada a la instancia de clase. Dejar la función original sin cambios.

acostado
fuente
2

Lo que Jason Pratt publicó es correcto.

>>> 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'>

Como puede ver, Python no considera que b () sea diferente a a (). En Python, todos los métodos son solo variables que resultan ser funciones.

Puntiagudo
fuente
77
Estás parcheando la clase Test, no una instancia de ella.
Ethan Furman
Estás agregando un método a una clase, no a una instancia de objeto.
TomSawyer
2

Me resulta extraño que nadie haya mencionado que todos los métodos enumerados anteriormente crean una referencia de ciclo entre el método agregado y la instancia, lo que hace que el objeto sea persistente hasta la recolección de basura. Había un viejo truco que agregaba un descriptor al extender la clase del objeto:

def addmethod(obj, name, func):
    klass = obj.__class__
    subclass = type(klass.__name__, (klass,), {})
    setattr(subclass, name, func)
    obj.__class__ = subclass
Yu Feng
fuente
2
from types import MethodType

def method(self):
   print 'hi!'


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

Con esto, puede usar el puntero automático

Arturo Morales Rangel
fuente