may - Agregando atributos a instancemethods en Python
static class python (2)
Me topé con este comportamiento al intentar que los decoradores de clases y los decoradores de métodos jugaran 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 la clase vendría después y completaría el valor más adelante. Este es un ejemplo simplificado
>>> 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, aunque cow.moo.thing
claramente me da 10? ¿Y por qué cow.moo.__func__.thing = 5
funciona? No tengo idea de por qué lo hace, pero al azar jugando con cosas en la lista de dir(cow.moo)
tratando de hacer que algo funcione, de repente lo hizo, y no tengo idea de por qué.
Para la búsqueda de atributos, Python está utilizando automáticamente la función real adjunta al método de instancia.
Para la configuración de atributos, no lo es.
Son dos operaciones separadas según el lado de la declaración en la que se encuentre, aunque ambas usan el .
operador.
Cuando accede al __func__
un método de __func__
, está accediendo manualmente a la función real que realmente tiene el atributo moo
.
En Python 3, esto funcionará como le gustaría o esperaría, ya que los métodos son básicamente funciones.
Si está buscando modificar los atributos de función de ambas funciones y métodos de instancia desde C, debe verificar el tipo de llamada que tiene.
Entonces, asumiendo que tienes un PyObject de algún tipo de llamada, puedes verificarlo así:
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 agf señaló que funciona desde Python para los métodos de ejemplo. Si solo intento establecer el atributo del método de instancia, no encontrará el atributo, no importa 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é se necesitaba cambiar. Pensé que alguien encontraría esta pregunta y respondería de nuevo mientras buscaba cómo resolver este problema a través de C.
Edición: Nota: Esto es para Python 2.7.x. Python 3.x usa diferentes llamadas a funciones.