2011-08-11 19 views
30

Me encontré con este comportamiento cuando intentaba que los decoradores de clases y los decoradores de métodos jugaran muy bien juntos. Esencialmente, los decoradores del método marcarían algunos de los métodos como especiales con algún valor ficticio, y el decorador de clases vendría después y llenaría el valor más tarde. Este es un ejemplo simplificadoAgregando atributos a métodos de instancias en Python

>>> class cow: 
>>>  def moo(self): 
>>>   print 'mooo' 
>>>  moo.thing = 10 
>>> 
>>> cow.moo.thing 
10 
>>> cow().moo.thing 
10 
>>> cow.moo.thing = 5 
AttributeError: 'instancemethod' object has no attribute 'thing' 
>>> cow().moo.thing = 5 
AttributeError: 'instancemethod' object has no attribute 'thing' 
>>> cow.moo.__func__.thing = 5 
>>> cow.moo.thing 
5 

¿Alguien sabe por qué cow.moo.thing = 5 no funciona, a pesar de que cow.moo.thing me da bastante claridad 10? ¿Y por qué funciona el cow.moo.__func__.thing = 5? No tengo idea de por qué lo hace, pero al azar jugando con cosas en la lista dir(cow.moo) tratando de hacer que algo funcione, de repente lo hizo, y no tengo idea de por qué.

Respuesta

33

Para la búsqueda de atributos, Python está utilizando automáticamente la función real adjunta al método de instancia para usted.

Para la configuración de atributos, no lo es.

Son dos operaciones independientes según el lado de la instrucción en el que se encuentre, aunque ambos usan el operador ..

Al acceder al método de instancia __func__, está accediendo manualmente a la función real que realmente tiene el atributo moo.

En Python 3 esto funcionará como te gustaría/espera, ya que los métodos son básicamente solo funciones.

+0

Ah bien, nunca lo supe. ¡Gracias! –

+0

Lo siento por revivir una publicación anterior, pero en Python3 'cow(). Moo.thing = 5' está devolviendo' AttributeError: 'method' object no tiene ningún atributo 'thing''. Sabes por qué ? –

+0

@JacquesGaudin En la instancia ('cow(). Moo') la función está envuelta en un objeto de método en cualquier versión de Python - la diferencia está en la clase (' cow.moo') no está envuelta en Python 3. La envoltura es necesaria para que el "self" pase automáticamente a la función. – agf

3

Si está buscando modificar los atributos de función de ambas funciones y los métodos de instancia de C, debe verificar el tipo de llamante que tiene.

Así que suponiendo que tiene una PyObject de algún tipo de exigible se puede comprobar de esta manera:

PyObject *callable; // set to something callable 
PyObject *setting; // set to something 
if(PyMethod_Check(callable)){ 
    PyObject_SetAttrString(PyMethod_Function(callable),"attribute",setting); 
}else{ 
    PyObject_SetAttrString(callable,"attribute",setting); 
} 
... 
// and the inverse 
if(PyMethod_Check(callable){   
    if(PyObject_HasAttrString(PyMethod_Function(callable),"attribute")){ 
     PyObject_DelAttrString(PyMethod_Function(callable),"attribute"); 
    } 
    }else{ 
    if(PyObject_HasAttrString(callable,"attribute")){ 
     PyObject_DelAttrString(callable,"attribute"); 
    } 
    } 

Ahora el código de AGF señalado funciona desde dentro de Python para los métodos de instancia. Si solo intento establecer el atributo del método de instancia, no encontraría el atributo sin importar cómo intenté acceder a él desde Python.

Me encontré con este problema y la pregunta de Li Haoyi con la respuesta de agf me ayudó a entender qué debía cambiarse. Supuse que alguien se encuentra esta pregunta y la respuesta de nuevo mientras se busca la manera de resolver este problema a través de C.

Editar: Nota: Esto es para Python 2.7.x. Python 3.x usa diferentes llamadas a funciones.

Cuestiones relacionadas