Agregar un método a una instancia de objeto existente -- python campo con oop campo con methods campo con monkeypatching camp Relacionados El problema

Adding a Method to an Existing Object Instance


682
vote

problema

Español

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?

Original en ingles

I've read that it is possible to add a method to an existing object (i.e., not in the class definition) in Python.

I understand that it's not always good to do so. But how might one do this?

</div
           

Lista de respuestas

973
 
vote
vote
La mejor respuesta
 

En Python, existe una diferencia entre las funciones y los métodos unidos.

  >>> 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 encuadernados se han "encado" (cuán descriptivo) a una instancia, y esa instancia se pasará como el primer argumento cada vez que se llame el método.

Callables que son atributos de una clase (a diferencia de una instancia) aún no están sin consolidar, por lo que puede modificar la definición de clase siempre que 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   

También se actualizan las instancias definidas previamente (siempre y cuando no hayan anulado los atributos):

  >>> a.fooFighters() fooFighters   

El problema viene cuando desea conectar 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 limita automáticamente cuando se adjunta directamente a una instancia:

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

Para enlazarlo, podemos usar el Función de método 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'   

Se puede encontrar más información leyendo sobre descriptores y metaclass programación .

 

In Python, there is a difference between functions and bound methods.

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

Bound methods have been "bound" (how descriptive) to an instance, and that instance will be passed as the first argument whenever the method is called.

Callables that are attributes of a class (as opposed to an instance) are still unbound, though, so you can modify the class definition whenever you want:

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

Previously defined instances are updated as well (as long as they haven't overridden the attribute themselves):

>>> a.fooFighters() fooFighters 

The problem comes when you want to attach a method to a single instance:

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

The function is not automatically bound when it's attached directly to an instance:

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

To bind it, we can use the MethodType function in the types module:

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

This time other instances of the class have not been affected:

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

More information can be found by reading about descriptors and metaclass programming.

</div
 
 
       
       
100
 
vote

módulo nuevo está desaprobado desde Python 2.6 y se elimina en 3.0, use tipos

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

En el siguiente ejemplo, he eliminado deliberadamente el valor de retorno de patch_me() Function. Creo que el valor de devolución puede hacer que uno crea que el parche devuelve un nuevo objeto, que no es cierto, modifica el entrante. Probablemente esto puede facilitar un uso más disciplinado de 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 <class '__main__.A'>   
 

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

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

In the example below I've deliberately removed return value from patch_me() function. I think that giving return value may make one believe that patch returns a new object, which is not true - it modifies the incoming one. Probably this can facilitate a more disciplined use of 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 <class '__main__.A'> 
</div
 
 
 
 
97
 
vote

Prefacio: una nota sobre la compatibilidad: otras respuestas solo pueden trabajar en Python 2: esta respuesta debe funcionar perfectamente en Python 2 y 3. Si está escribiendo solo Python 3, podría dejar de lado exherir explícitamente de object , pero de lo contrario el código debe seguir siendo el mismo.

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

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

Aquí hay un par de razones:

  • Agregarás un objeto unido a cada instancia a la que hagas esto. Si haces esto mucho, probablemente perderás mucha memoria. Los métodos encuadernados generalmente se crean solo por la corta duración de su llamada, y luego dejan de existir cuando se recolectan automáticamente la basura. Si hace esto manualmente, tendrá una obligación de nombre que reference al método encuadernado, que evitará su recolección de basura en el uso.
  • Las instancias de objetos de un tipo dado generalmente tienen sus métodos en todos los objetos de ese tipo. Si agrega métodos en otra parte, algunas instancias tendrán esos métodos y otros no lo harán. Los programadores no esperarán esto, y usted se arriesga a violar la regla de lo menos sorpresa .
  • Ya que hay otras buenas razones para no hacer esto, además te darás una mala reputación si lo haces.

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

  Foo.sample_method = sample_method   

Dado que es instructivo, sin embargo, te voy a mostrar algunas formas de hacer esto.

Cómo se puede hacer

Aquí hay algún código de configuración. Necesitamos una definición de clase. Podría ser importado, pero realmente no importa.

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

Crear una instancia:

  foo = Foo()   

Crear un método para agregarlo:

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

Método NADE (0) - Use el método del descriptor, __get__

Búsquedas de puntos en las funciones Llame al método __get__6 de la función con la instancia, vinculando el objeto al método y, por lo tanto, creando un "método unido".

  foo.sample_method = sample_method.__get__(foo)   

y ahora:

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

Método uno - tipos.MethodType

Primero, tipos de importación, desde los cuales obtendremos el método constructor:

  import types   

Ahora agregamos el método a la instancia. Para hacer esto, requerimos el constructor METHTYTYPE del módulo Foo.sample_method = sample_method 0 (que importamos anteriormente).

La firma de argumento para tipos.methodtype es Foo.sample_method = sample_method 111 :

  Foo.sample_method = sample_method 2  

y uso:

  Foo.sample_method = sample_method 3  

Método Dos: unión léxica

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

  Foo.sample_method = sample_method 4  

Uso:

  Foo.sample_method = sample_method 5  

Método Tres: Functools.Partial

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

  Foo.sample_method = sample_method 6  

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

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

Si intentamos agregar el Sample_Method de la misma manera que podríamos agregarlo a la clase, no se puede unir de la instancia, y no se toma el Ser implícito como el primer argumento.

  Foo.sample_method = sample_method 7  

Podemos hacer que la función no unida funcione explícitamente, pasando explícitamente la instancia (o cualquier cosa, ya que este método no usa la variable __get__18 ARGUMENTE), pero no sería consistente con la firma esperada de otros casos (si somos Monkey-Patching este caso):

  Foo.sample_method = sample_method 9  

Conclusión

Ahora sabe varias maneras en que usted podría hacer esto, pero en toda seriedad, no hagas esto.

 

Preface - a note on compatibility: other answers may only work in Python 2 - this answer should work perfectly well in Python 2 and 3. If writing Python 3 only, you might leave out explicitly inheriting from object, but otherwise the code should remain the same.

Adding a Method to an Existing Object Instance

I've read that it is possible to add a method to an existing object (e.g. not in the class definition) in Python.

I understand that it's not always a good decision to do so. But, how might one do this?

Yes, it is possible - But not recommended

I don't recommend this. This is a bad idea. Don't do it.

Here's a couple of reasons:

  • You'll add a bound object to every instance you do this to. If you do this a lot, you'll probably waste a lot of memory. Bound methods are typically only created for the short duration of their call, and they then cease to exist when automatically garbage collected. If you do this manually, you'll have a name binding referencing the bound method - which will prevent its garbage collection on usage.
  • Object instances of a given type generally have its methods on all objects of that type. If you add methods elsewhere, some instances will have those methods and others will not. Programmers will not expect this, and you risk violating the rule of least surprise.
  • Since there are other really good reasons not to do this, you'll additionally give yourself a poor reputation if you do it.

Thus, I suggest that you not do this unless you have a really good reason. It is far better to define the correct method in the class definition or less preferably to monkey-patch the class directly, like this:

Foo.sample_method = sample_method 

Since it's instructive, however, I'm going to show you some ways of doing this.

How it can be done

Here's some setup code. We need a class definition. It could be imported, but it really doesn't matter.

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

Create an instance:

foo = Foo() 

Create a method to add to it:

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

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

Dotted lookups on functions call the __get__ method of the function with the instance, binding the object to the method and thus creating a "bound method."

foo.sample_method = sample_method.__get__(foo) 

and now:

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

Method one - types.MethodType

First, import types, from which we'll get the method constructor:

import types 

Now we add the method to the instance. To do this, we require the MethodType constructor from the types module (which we imported above).

The argument signature for types.MethodType is (function, instance, class):

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

and usage:

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

Method two: lexical binding

First, we create a wrapper function that binds the method to the 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 

Method three: functools.partial

A partial function applies the first argument(s) to a function (and optionally keyword arguments), and can later be called with the remaining arguments (and overriding keyword arguments). Thus:

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

This makes sense when you consider that bound methods are partial functions of the instance.

Unbound function as an object attribute - why this doesn't work:

If we try to add the sample_method in the same way as we might add it to the class, it is unbound from the instance, and doesn't take the implicit self as the first 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) 

We can make the unbound function work by explicitly passing the instance (or anything, since this method doesn't actually use the self argument variable), but it would not be consistent with the expected signature of other instances (if we're monkey-patching this instance):

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

Conclusion

You now know several ways you could do this, but in all seriousness - don't do this.

</div
 
 
         
         
37
 
vote

Creo que las respuestas anteriores se perdieron el punto clave.

Vamos a tener una clase con un método:

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

Ahora, vamos a jugar 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 para 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 que se agrega a a Diccionario de clase: no hay magia. Entonces, ¿por qué a.m nos da un método no unido? Es porque el punto no está traducido a una simple búsqueda de diccionarios. Es de facto una llamada de un .__ 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 la parte superior de mi cabeza por qué la última línea se imprime dos veces, pero aún está claro lo que está pasando allí.

Ahora, lo que hace el valor predeterminado __getattribute__ es que comprueba si el atributo es el llamado descriptor o no, es decir, si implementa un método especial __get__. Si implementa ese método, entonces 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 del descriptor, si se les llama en nombre de un objeto, se unen a ese objeto en su método __get__.

OK, ¿cómo agregar un método a un objeto existente? Suponiendo que no le importa la clase de parches, es tan simple como:

  B.m = m   

luego b.m "se convierte en" un método no unido, gracias a la magia del descriptor.

y si desea agregar un método solo a un solo objeto, entonces tiene que emular la maquinaria usted mismo, usando tipos.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'>   
 

I think that the above answers missed the key point.

Let's have a class with a method:

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

Now, let's play with it in ipython:

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

Ok, so m() somehow becomes an unbound method of A. But is it really like that?

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

It turns out that m() is just a function, reference to which is added to A class dictionary - there's no magic. Then why A.m gives us an unbound method? It's because the dot is not translated to a simple dictionary lookup. It's de facto a call of A.__class__.__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 

Now, I'm not sure out of the top of my head why the last line is printed twice, but still it's clear what's going on there.

Now, what the default __getattribute__ does is that it checks if the attribute is a so-called descriptor or not, i.e. if it implements a special __get__ method. If it implements that method, then what is returned is the result of calling that __get__ method. Going back to the first version of our A class, this is what we have:

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

And because Python functions implement the descriptor protocol, if they are called on behalf of an object, they bind themselves to that object in their __get__ method.

Ok, so how to add a method to an existing object? Assuming you don't mind patching class, it's as simple as:

B.m = m 

Then B.m "becomes" an unbound method, thanks to the descriptor magic.

And if you want to add a method just to a single object, then you have to emulate the machinery yourself, by using types.MethodType:

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

By the way:

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'> 
</div
 
 
20
 
vote

En Python MonkeyPatching generalmente funciona al sobrescribir la firma de una clase o función con la suya propia. A continuación se muestra un ejemplo de la zope wiki :

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

Este código sobrescribirá / creará un método llamado peak en la clase. En Jeff At Atwood's Publicación reciente en Monkey Parching , mostró un ejemplo en C # 3.0, que Es el idioma actual que uso para el trabajo.

 

In Python monkeypatching generally works by overwriting a class or function's signature with your own. Below is an example from the Zope Wiki:

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

This code will overwrite/create a method called peak in the class. In Jeff Atwood's recent post on monkey patching, he showed an example in C# 3.0 which is the current language I use for work.

</div
 
 
 
 
15
 
vote

Puede usar Lambda para enlazar un método a una instancia:

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

Salida:

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

You can use lambda to bind a method to an instance:

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

Output:

This is instance string 
</div
 
 
9
 
vote

Hay al menos dos formas para adjuntar un método a una instancia sin In [2]: A.m Out[2]: <unbound method A.m> 2 :

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

1:

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

2:

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

Enlaces útiles:
Modelo de datos - Invoca descriptores
Descriptor HowTo Guía - Invoca descriptores

 

There are at least two ways for attach a method to an instance without 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>> 

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

</div
 
 
8
 
vote

Lo que está buscando es In [2]: A.m Out[2]: <unbound method A.m> 6 creo. Use esto para establecer un atributo en un objeto.

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

What you're looking for is setattr I believe. Use this to set an attribute on an object.

>>> 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> 
</div
 
 
     
     
6
 
vote

Dado que esta pregunta solicitó las versiones de no Python, aquí está Javascript:

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

Since this question asked for non-Python versions, here's JavaScript:

a.methodname = function () { console.log("Yay, a new method!") } 
</div
 
 
5
 
vote

Consolidando a Jason Pratt's y la comunidad Wiki responde, con un vistazo a los resultados de diferentes métodos de unión:

Nota especialmente Cómo agregar la función de enlace como método de clase funciona , pero el alcance de referencia es incorrecto.

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

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

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

Consolidating Jason Pratt's and the community wiki answers, with a look at the results of different methods of binding:

Especially note how adding the binding function as a class method works, but the referencing scope is incorrect.

#!/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 x = %d r = %d' % ( x, self.r)  a = C() # created before modified instnace b = C() # modified instnace   def f1(self, x): # bind internally     print 'f1 x = %d r = %d' % ( x, self.r ) def f2( self, x): # add to class instance's .__dict__ as method type     print 'f2 x = %d r = %d' % ( x, self.r ) def f3( self, x): # assign to class as method type     print 'f3 x = %d r = %d' % ( x, self.r ) def f4( self, x): # add to class instance's .__dict__ using a general function     print 'f4 x = %d r = %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 ' attributes 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 ' attributes 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 ' attributes 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>> 

Personally, I prefer the external ADDMETHOD function route, as it allows me to dynamically assign new method names within an iterator as well.

def y(self, x):     pass d = C() for i in range(1,5):     ADDMETHOD(d, y, 'f%d' % i) print ' attributes 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>> 
</div
 
 
5
 
vote

Este es en realidad un adicto a la respuesta de "Jason Pratt"

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

Me llevó a las edades encontrar una solución alternativa, pero el truco parece simple ... 1. importar el código del archivo de código fuente 2.nd fuerza una recarga 3.er tipos de uso. FunctyType (...) para convertir el método importado y enlazado 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 puedes continuar según lo sugerido por "Jason Pratt" usando los tipos.methodtype (...)

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   
 

This is actually an addon to the answer of "Jason Pratt"

Although Jasons answer works, it does only work if one wants to add a function to a class. It did not work for me when I tried to reload an already existing method from the .py source code file.

It took me for ages to find a workaround, but the trick seems simple... 1.st import the code from the source code file 2.nd force a reload 3.rd use types.FunctionType(...) to convert the imported and bound method to a function you can also pass on the current global variables, as the reloaded method would be in a different namespace 4.th now you can continue as suggested by "Jason Pratt" using the types.MethodType(...)

Example:

# 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 
</div
 
 
3
 
vote

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

Uso de una función needle() Para parchear un módulo llamado guineapig va la siguiente:

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

Pero también se ocupa de los casos de uso más interesantes, como se muestra en la Preguntas frecuentes Desde la documentación .

El código está disponible en github .

 

If it can be of any help, I recently released a Python library named Gorilla to make the process of monkey patching more convenient.

Using a function needle() to patch a module named guineapig goes as follows:

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

But it also takes care of more interesting use cases as shown in the FAQ from the documentation.

The code is available on GitHub.

</div
 
 
3
 
vote

Esta pregunta se abrió hace años, pero oye, hay una manera fácil de simular la unión 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 pasa la función y la instancia al decorador de la carpeta, creará una nueva función, con el mismo objeto de código que el primero. 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 llamando automáticamente la función copiada, dando la instancia como el primer parámetro.

En conclusión, obtiene una función que simula que es vinculante a la instancia de clase. Dejar que la función original sin cambios.

 

This question was opened years ago, but hey, there's an easy way to simulate the binding of a function to a class instance using decorators:

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.

</div
 
 
2
 
vote

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 se considera B () a ninguna diferente a A (). En Python, todos los métodos son solo variables que son funciones.

 

What Jason Pratt posted is correct.

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

As you can see, Python doesn't consider b() any different than a(). In Python all methods are just variables that happen to be functions.

</div
 
 
   
   
2
 
vote

Me parece extraño que nadie mencione 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. Hubo un truco antiguo agregando un descriptor extendiendo la clase del objeto:

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

I find it strange that nobody mentioned that all of the methods listed above creates a cycle reference between the added method and the instance, causing the object to be persistent till garbage collection. There was an old trick adding a descriptor by extending the class of the object:

def addmethod(obj, name, func):     klass = obj.__class__     subclass = type(klass.__name__, (klass,), {})     setattr(subclass, name, func)     obj.__class__ = subclass 
</div
 
 
2
 
vote
  from types import MethodType  def method(self):    print 'hi!'   setattr( targetObj, method.__name__, MethodType(method, targetObj, type(method)) )   

Con esto, puedes usar el auto puntero

 
from types import MethodType  def method(self):    print 'hi!'   setattr( targetObj, method.__name__, MethodType(method, targetObj, type(method)) ) 

With this, you can use the self pointer

</div
 
 
0
 
vote

Aparte de lo que otros dijeron, encontré que __repr__ y __str__ no pueden ser monkeypatched en nivel de objeto, ya que 99887776610 y < CÓDIGO> needle()11111111- MÉTODOS DE CLASE, NO MÉTODOS DE OBJETIVO LOTIDADOS:

  needle()2  
 

Apart from what others said, I found that __repr__ and __str__ methods can't be monkeypatched on object level, because repr() and str() use class-methods, not locally-bounded object methods:

# Instance monkeypatch [ins] In [55]: x.__str__ = show.__get__(x)                                                                   [ins] In [56]: x                                                                                            Out[56]: <__main__.X at 0x7fc207180c10>  [ins] In [57]: str(x)                                                                                       Out[57]: '<__main__.X object at 0x7fc207180c10>'  [ins] In [58]: x.__str__()                                                                                  Nice object!  # Class monkeypatch [ins] In [62]: X.__str__ = lambda _: "From class"                                                            [ins] In [63]: str(x)                                                                                       Out[63]: 'From class' 
</div
 
 

Relacionados problema

6  ¿Cómo se ocupa SmallTalk con monkeypatching?  ( How does smalltalk deal with monkeypatching ) 
Soy un codificador de rubí. Para mí, MonkeyPatching es cambiar, en tiempo de ejecución, clases o métodos de módulos en un proyecto externo. En lo que me inter...

0  Pruebas de la unidad de Python con simulacro y parchear un módulo de módulo extranjero  ( Python unit testing with mock and patch a foreign modul ) 
Me gustaría probar una clase que use la clase serial del modul serial. Sé que tengo que burlarlos, pero no lo entiendo y corriendo: from serial import Seri...

1  Pytest Monkeypatch falla la segunda vez se llama  ( Pytest monkeypatch fails second time is called ) 
Hola, estoy intentando usar, use Pytest para probar algunos métodos de una aplicación de AppEngine. Ambos métodos utilizan google.appengine.api.users.get_cur...

3  La aplicación PY2APP'ED se ejecuta correctamente en el modo de alias, pero no cuando se incluye  ( Py2apped application runs properly in alias mode but not when bundled ) 
Tengo una aplicación PYOBJC que se ejecuta en una construcción de Python solo de 32 bits que hace uso de la biblioteca GEVENT. Todo funciona muy bien en el mo...

1  ¿Es teóricamente seguro para redefinir cualquier método de rubí que no comience con los subrayadores?  ( Is it theoretically safe to redefine any ruby method that doesnt begin with und ) 
Por ejemplo, es teóricamente seguro para modificar Object#object_id ya que siempre hay Object#__id__ Si realmente necesita saber qué es la identificación ...

1  Monkey parchey One jquery ui autocompletar render artículo  ( Monkey patching one jquery ui autocomplete render item ) 
driver.findElement(By.name("Dec")).sendKeys("Jan"); 111 desde aquí ¿Qué está haciendo este bit driver.findElement(By.name("Dec")).sendKeys("Jan"); 2 ...

19  Gevent Monkey-Patching y Puntos de interrupción  ( Gevent monkey patching and breakpoints ) 
He estado jugando con gevent, y me gusta mucho. Sin embargo, me he encontrado con un problema. El punto de interrupción no se está poniendo en el golpe, y la ...

0  ¿Por qué necesitaría compilar / generar métodos / código en tiempo de ejecución?  ( Why would i need to compile generate methods code at runtime ) 
Estoy interesado en el aspecto teórico. ¿Cuál es la necesidad en C # para usar codedom / reflexión o lambda expresiones / expresión de árboles para generar có...

3  Es bcel == monkeypatching para java?  ( Is bcel monkeypatching for java ) 
Un colega me señaló el otro día para bcel que, lo mejor que puedo decir por su Explicación y una lectura rápida, una forma de modificar en tiempo de ejecuci...

682  Agregar un método a una instancia de objeto existente  ( Adding a method to an existing object instance ) 
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...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos