2012-03-01 38 views
8

我想在我的一个类中为实例方法添加属性。我试过this question给出的答案,但这个答案只适用于函数 - 据我所知。将属性添加到Python中的实例方法

举个例子,我希望能够做这样的事情:

class foo(object): 
    ... 
    def bar(self): 
     self.bar.counter += 1 
     return self.bar.counter 
    bar.counter = 1 
    ... 

,但是,当我调用foo()巴()我得到:

AttributeError: 'instancemethod' object has no attribute 'counter' 

我的目标这样做的目的是试图说明'counter'变量是bar()方法的局部变量,也是为了避免使用另一个属性混淆我的类名称空间。有没有办法做到这一点?是否有更多pythonic这样做?

+0

应该'counter'是一流的水平(所有实例共享当前计),或实例级别(每个实例会从1开始)? – 2012-03-01 21:50:34

+0

'计数器'应该是实例级别 – sbell 2012-03-01 21:54:30

+0

此相关的问题可能(或可能不会)有所帮助:http://stackoverflow.com/questions/7034063/adding-attributes-the-instancemethods-in-python – 2012-03-01 22:11:10

回答

8

在Python 3中,你的代码可以工作,但是在Python 2中,当查找方法时会发生一些包装。

类VS实例

  • 类级别:存储counter用函数(直接,或通过使用一个可变的默认值)有效地使得一个类级别属性,因为这里只有永远该函数的一个,不管你有多少个实例(它们都共享相同的函数对象)。

  • 实例级别:使counter实例级别属性必须在__init__创建功能,然后用functools.partial包起来(因此它的行为像一个正常的方法),然后将其存储在实例 - 现在你每个实例都有一个函数对象。

职业等级

一个静态类变量上通行的做法是使用可变默认参数:如果你希望它是更漂亮,你可以定义自己的可变

class foo(object): 
    ... 
    def bar(self, _counter=[0]): 
     _counter[0] += 1 
     return _counter[0] 

集装箱:

class MutableDefault(object): 
    def __init__(self, start=0): 
     self.value = start 
    def __iadd__(self, other): 
     self.value += other 
     return self 
    def value(self): 
     return self.value 

和改变,像这样的代码:

class foo(object): 
    def bar(self, _counter=MutableDefault()): 
     _counter += 1 
     return _counter.value 

实例级别

from functools import partial 

class foo(object): 
    def __init__(self): 
     def bar(self, _counter=MutableDefault(1)): # create new 'bar' each time 
      value = _counter.value 
      _counter += 1 
      return value 
     self.bar = partial(bar, self) 

摘要

正如你所看到的,可读性移动到实例级别counter当把一个严重的打击。我强烈建议你重新强调一下counterbar的一部分的重要性,并且如果它真的很重要,可能使bar是其自己的类,其实例成为foo的实例的一部分。如果不是真的很重要,这样做的正常方式:

class foo(object): 
    def __init__(self): 
     self.bar_counter = 0 
    def bar(self): 
     self.bar_counter += 1 
     return self.bar_counter 
+0

请注意,'MutableDefault'不是接近完整实现的地方 - 这是读者的练习。 :) – 2012-03-01 20:57:23

+0

默认参数只评估一次,所以它是类级别的。 OP在对该问题的评论中澄清说它应该是实例级的。 – 2012-03-01 22:09:57

+0

@ Series8217:是的,这就是为什么我问这个问题 - 更新答案以显示如何在实例级别执行此操作。 – 2012-03-01 23:25:17

0

您需要一个__init__方法来初始化数据成员:

class foo(object): 
    def __init__(self): 
     self.counter = 0 
    def bar(self): 
     self.counter += 1 
     return self.counter 

直接附加的数据值的功能是断然非Python化。

+0

我很欣赏这一点,但我的目标是将计数器变量绑定到条形方法(出于我在我的问题中提到的原因)。我修改你的答案: 类Foo(对象): 高清__init __(个体经营): self.bar.counter = 0 高清条(个体经营): self.bar.counter + = 1 回报self.bar .counter 但现在我在__init__调用中得到相同的AttributeError – sbell 2012-03-01 20:25:53

+0

不像请求的OP那样将'counter'绑定到'bar'。 – 2012-03-01 20:45:34

+0

@EthanFurman:OP要求采取“更pythonic”的方式来做到这一点。直接将数据附加到函数与Pythonic相反。 – 2012-03-01 20:46:59

0

如果您希望计数器在所有实例中保持不变,您可以执行以下操作,但这仍然不是Pythonic。

class foo(object): 
    def bar(self): 
     self.bar.im_func.counter += 1 
     return self.bar.im_func.counter 
    bar.counter = 0 
相关问题