在函数体内更改函数的属性?

Change an attribute of a function inside its own body?

我正在尝试创建一个函数来记录它被调用的次数,我希望信息保留在函数本身中。 我尝试像这样创建一个包装器:

def keep_count(f):
    f.count = 0
    @functools.wraps(f)
    def wrapped_f(*args, **kwargs):
        f(*args, **kwargs)
        f.count += 1
    return wrapped_f

@keep_count
def test_f(*args, **kwargs):
    print(args, kwargs)

我认为它会起作用,但我得到一个 AttributeError'function' object has no attribute 'count'

我已经解决了这个问题:这是因为装饰器将我的 test_f 设置为等于 wrapped_f(在 keep_count 装饰器内部定义),我正在增加计数原来的 f,因为 test_f 指的是新函数,所以不再使用。

有没有办法不用太多黑客攻击就可以做到这一点?

只需在 wrapped_f 而不是 f 上设置属性。这需要你在定义函数后设置初始count,但这没什么大不了的:

def keep_count(f):
    @functools.wraps(f)
    def wrapped_f(*args, **kwargs):
        f(*args, **kwargs)
        wrapped_f.count += 1
    wrapped_f.count = 0
    return wrapped_f

然后用你的修饰函数:

>>> test_f()
() {}
>>> test_f.count
1
>>> test_f()
() {}
>>> test_f.count
2

之所以有效,是因为 wrapped_fkeep_count 中的局部变量。由于 wrapped_f 的主体包含对 wrapped_f 的引用,它得到一个允许 wrapped_f 访问自身的闭包。