sbe*_*ell 10 python methods instance instance-methods
我想在我的一个类中为实例方法添加一个属性.我尝试了这个问题给出的答案,但这个答案只适用于函数 - 据我所知.
举个例子,我希望能够做到这样的事情:
class foo(object):
...
def bar(self):
self.bar.counter += 1
return self.bar.counter
bar.counter = 1
...
Run Code Online (Sandbox Code Playgroud)
但是,当我调用foo().bar()时,我得到:
AttributeError: 'instancemethod' object has no attribute 'counter'
Run Code Online (Sandbox Code Playgroud)
我这样做的目的是试图强调'counter'变量是bar()方法的本地变量,并且还避免使用另一个属性混乱我的类名称空间.有没有办法做到这一点?有更多的pythonic方式吗?
在Python 3中,您的代码可以正常工作,但在Python 2中,在查找方法时会发生一些包装.
类级别:counter使用函数存储(直接或使用可变默认值)有效地使它成为类级别属性,因为只有一个函数,无论你有多少个实例(它们都共享相同的函数对象) ).
实例级别:要创建counter一个实例级别属性,您必须创建该函数__init__,然后将其包装functools.partial(因此它的行为类似于普通方法),然后将其存储在实例上 - 现在每个实例都有一个函数对象.
静态类变量的公认惯例是使用可变的默认参数:
class foo(object):
...
def bar(self, _counter=[0]):
_counter[0] += 1
return _counter[0]
Run Code Online (Sandbox Code Playgroud)
如果你想让它更漂亮,你可以定义自己的可变容器:
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
Run Code Online (Sandbox Code Playgroud)
并像这样更改您的代码:
class foo(object):
def bar(self, _counter=MutableDefault()):
_counter += 1
return _counter.value
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,可移植性在转移到实例级别时受到了严重影响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
Run Code Online (Sandbox Code Playgroud)