Добавление атрибутов к методам экземпляров в Python - PullRequest
32 голосов
/ 12 августа 2011

Я столкнулся с таким поведением, когда пытался заставить класс-декораторы и методы-декораторы хорошо играть вместе. По сути, декораторы методов помечают некоторые методы как особые с некоторым фиктивным значением, а декоратор класса приходит после и заполняет значение позже. Это упрощенный пример

>>> 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), пытаясь заставить что-то работать, это неожиданно получилось, и я не знаю почему.

Ответы [ 2 ]

35 голосов
/ 12 августа 2011

Для поиска атрибутов Python автоматически использует реальную функцию, прикрепленную к методу экземпляра.

Для настройки атрибута это не так.

Это две отдельные операции, в зависимости от того, на какой стороне оператора вы находитесь, хотя они обе используют оператор ..

Когда вы обращаетесь к __func__ метода экземпляра, вы вручную получаете доступ к реальной функции, которая на самом деле имеет атрибут moo.

В Python 3 это будет работать так, как вы хотите / ожидаете, так как методы в основном просто функции.

3 голосов
/ 02 декабря 2012

Если вы хотите изменить атрибуты функций как функций, так и методов экземпляра из 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 использует различные вызовы функций.

...