如何创建实例特定的函数计数器?

How to create instance specific function counter?

我想跟踪 class 中的函数计数,但 class 的每个实例的计数都不同。

我们可以在一个简单的函数上设置一个计数器:

def foo1():
    pass

foo1.count = 0
foo1.count +=1
print(foo1.count)

现在让我们转向 class 方法:

class A:
    def foo2(self):
        print('Hi')

这里也可以设置计数器

A.foo2.count = 0
a = A()
b = A()

但此计数不是特定于实例的

A.foo2.count += 1
print(a.foo2.count)
print(b.foo2.count)

无法为 INSTANCE 方法设置计数:

a.foo2.count += 1

如果我们使用 __func__ 则相当于更改 A.foo2.count:

a.foo2.__func__.count += 1
print(b.foo2.count)
print(a.foo2.count)
print(A.foo2.count)

问题:如何使foo2.countINSTANCE具体化?这样 ab 可以有多个值 foo2.count ?

请注意:我问的是 function 属性,而不是 class 属性。

使用__init__方法:

class A:

    def __init__(self):
        self.count_foo2 = 0

    def foo2(self):
        print('Hi')
        self.count_foo2 += 1 


a = A()
b = A()

a.foo2()

print(a.count_foo2)
print(b.count_foo2)

输出:

Hi
1
0

也许是这样?

from collections import defaultdict


def foo1():
    print('Hi')
foo1.count = defaultdict(int)

class A:

    def foo2(self):
        foo1()
        foo1.count[self] += 1



a = A()
b = A()

a.foo2()
a.foo2()
b.foo2()

print(foo1.count)

输出:

Hi
Hi
Hi
defaultdict(<class 'int'>, {<__main__.A object at 0x000001E59759ABE0>: 2, <__main__.A object at 0x000001E596AFCD30>: 1})

这是我的尝试。我不确定这是否完全是您想要的,因为在您的评论之一中您表示您想要特定的函数实例属性(?)。然而,这似乎 表现 您所描述的方式。无论您希望此行为发生多少方法,它都有工作的好处。

def fn_exec_count(base_fn):
    def new_fn(self, *args, **kwargs):
        fn_count_attr = 'fn_' + base_fn.__name__ + '_count'
        if not hasattr(self, fn_count_attr):
            setattr(self, fn_count_attr, 1)
        else:
            setattr(self, fn_count_attr, getattr(self, fn_count_attr) + 1)
        base_fn(self, *args, **kwargs)
    new_fn.__name__ = base_fn.__name__
    return new_fn

class A:
    @fn_exec_count
    def foo(self):
        fn_count_attr = 'fn_' + A.foo.__name__ + '_count' 
        print(f'Value of counter: {getattr(self, fn_count_attr, None)}')


a1 = A()
a1.foo()
a1.foo()
a2 = A()
a2.foo()
a1.foo()

输出:

Value of counter: 1
Value of counter: 2
Value of counter: 1
Value of counter: 3

编辑:从 Julien 的使用 defaultdict 的答案中窃取内容使这稍微不那么冗长。

def fn_exec_count_dict(base_fn):
    def new_fn(self, *args, **kwargs):
        if not hasattr(self, 'fn_exec_count'):
            setattr(self, 'fn_exec_count', defaultdict(int))
        self.fn_exec_count[base_fn.__name__] += 1
        base_fn(self, *args, **kwargs)
    new_fn.__name__ = base_fn.__name__
    return new_fn

class A:
    @fn_exec_count_dict
    def foo(self):
        print(f'Value of counter: {self.fn_exec_count[A.foo.__name__]}')

# ...