将属性添加到Python中的实例方法
我想在我的一个类中为实例方法添加属性。我试过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这样做?
在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
当把一个严重的打击。我强烈建议你重新强调一下counter
是bar
的一部分的重要性,并且如果它真的很重要,可能使bar
是其自己的类,其实例成为foo
的实例的一部分。如果不是真的很重要,这样做的正常方式:
class foo(object):
def __init__(self):
self.bar_counter = 0
def bar(self):
self.bar_counter += 1
return self.bar_counter
请注意,'MutableDefault'不是接近完整实现的地方 - 这是读者的练习。 :) – 2012-03-01 20:57:23
默认参数只评估一次,所以它是类级别的。 OP在对该问题的评论中澄清说它应该是实例级的。 – 2012-03-01 22:09:57
@ Series8217:是的,这就是为什么我问这个问题 - 更新答案以显示如何在实例级别执行此操作。 – 2012-03-01 23:25:17
您需要一个__init__
方法来初始化数据成员:
class foo(object):
def __init__(self):
self.counter = 0
def bar(self):
self.counter += 1
return self.counter
直接附加的数据值的功能是断然非Python化。
我很欣赏这一点,但我的目标是将计数器变量绑定到条形方法(出于我在我的问题中提到的原因)。我修改你的答案: 类Foo(对象): 高清__init __(个体经营): self.bar.counter = 0 高清条(个体经营): self.bar.counter + = 1 回报self.bar .counter 但现在我在__init__调用中得到相同的AttributeError – sbell 2012-03-01 20:25:53
不像请求的OP那样将'counter'绑定到'bar'。 – 2012-03-01 20:45:34
@EthanFurman:OP要求采取“更pythonic”的方式来做到这一点。直接将数据附加到函数与Pythonic相反。 – 2012-03-01 20:46:59
如果您希望计数器在所有实例中保持不变,您可以执行以下操作,但这仍然不是Pythonic。
class foo(object):
def bar(self):
self.bar.im_func.counter += 1
return self.bar.im_func.counter
bar.counter = 0
对不起挖了一个旧的文章,但我在搜索碰到它,居然发现有人用一个解决方案。
下面是一篇博客文章,描述了您遇到的问题以及如何创建一个能够满足您需要的装饰器。您不仅可以获得所需的功能,而且作者可以很好地解释Python为什么会这样工作。
http://metapython.blogspot.com/2010/11/python-instance-methods-how-are-they.html
应该'counter'是一流的水平(所有实例共享当前计),或实例级别(每个实例会从1开始)? – 2012-03-01 21:50:34
'计数器'应该是实例级别 – sbell 2012-03-01 21:54:30
此相关的问题可能(或可能不会)有所帮助:http://stackoverflow.com/questions/7034063/adding-attributes-the-instancemethods-in-python – 2012-03-01 22:11:10