在Python中为实例方法添加属性

34 投票
2 回答
7357 浏览
提问于 2025-04-16 23:26

我在尝试让类装饰器和方法装饰器一起正常工作时遇到了这个问题。简单来说,方法装饰器会给一些方法标记上特殊的值,然后类装饰器会在后面来填充这个值。这是一个简化的例子。

>>> 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 个回答

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访问它,都找不到这个属性。

我遇到了这个问题,Li Haoyi的问题和agf的回答帮助我理解了需要做哪些更改。我想会有人在寻找如何通过C语言解决这个问题时再次看到这个问题和答案。

编辑:注意:这是针对Python 2.7.x的。Python 3.x使用不同的函数调用方式。

37

在查找属性时,Python会自动为你使用与实例方法关联的真实函数。

但是在设置属性时,它就不是这样了。

这两者是不同的操作,取决于你在语句的哪一边,尽管它们都使用了.这个符号。

当你访问一个实例方法的__func__时,其实是在手动访问那个真正拥有moo属性的函数。

在Python 3中,这样的操作会像你想的那样正常工作,因为方法基本上就是函数。

撰写回答