当我试图让类装饰器和方法装饰器很好地一起玩时,我遇到了这种行为。从本质上讲,方法装饰器会将某些方法标记为特殊的一些虚拟值,并且类装饰器将在之后出现并稍后填充该值。这是一个简化的例子
>>> 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)
列表中的东西试图让某些东西起作用它突然间做了,我不明白为什么。
答案 0 :(得分:35)
对于属性查找,Python会自动使用附加到实例方法的实际函数。
对于属性设置,它不是。
它们是两个独立的操作,具体取决于您所使用的语句的哪一侧,即使它们都使用.
运算符。
当您访问实例方法的__func__
时,您手动访问实际具有moo
属性的实际函数。
在Python 3中,这将按照您希望/期望的方式工作,因为方法基本上只是函数。
答案 1 :(得分:3)
如果您要从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解决这个问题的同时找到这个问题并再次回答。
修改强> 注意:这适用于Python 2.7.x. Python 3.x使用不同的函数调用。