Добавление атрибутов к instancemethods в 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
Кто-нибудь знает, почему cow.moo.thing = 5
не работает, хотя cow.moo.thing
довольно ясно дает мне 10? И почему работает cow.moo.__func__.thing = 5
? Я понятия не имею, почему это происходит, но в случайном порядке перебирает вещи в списке dir(cow.moo)
, пытаясь заставить что-то работать, это внезапно, и я понятия не имею, почему.
Ответы
Ответ 1
Для поиска атрибутов Python автоматически использует реальную функцию, прикрепленную к вашему экземпляру.
Для настройки атрибута это не так.
Это две отдельные операции в зависимости от того, с какой стороны вы находитесь, хотя оба они используют оператор .
.
Когда вы обращаетесь к методу экземпляра __func__
, вы вручную обращаетесь к реальной функции, которая на самом деле имеет атрибут moo
.
В Python 3 это будет работать так, как вам хотелось бы/ожидать, поскольку методы в основном являются просто функциями.
Ответ 2
Если вы хотите изменить атрибуты функций обеих функций и методы экземпляра из C, вам необходимо проверить тип вызываемого вами вызова.
Итак, если у вас есть PyObject какого-либо типа вызываемого, вы можете его проверить следующим образом:
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");
}
}
Теперь код agf указал, что работает из методов Python, например. Если я просто попытаюсь установить атрибут метода экземпляра, он не найдет атрибут независимо от того, как я пытался получить доступ к нему из Python.
Я столкнулся с этой проблемой, и вопрос Ли Хаойи с ответом agf помог мне понять, что нужно изменить. Я решил, что кто-то найдет этот вопрос и ответит снова, ища, как решить эту проблему с помощью C.
Edit:
Примечание: это для Python 2.7.x. Python 3.x использует разные вызовы функций.