Этот вопрос был первоначально закрыт как дубликат к Как создать цепочку декораторов функций? , где правильно указано, что использование functools.wraps
для декорации цепочек может помочь путем копирования всех атрибутовобернутая функция к функции-обертке.
Однако я снова открываю этот вопрос, потому что использование functools.wraps
не будет работать полностью в вашем случае, поскольку ваш атрибут counter
является неизменным целым числом, поэтому наличие wraps
копирует атрибут counter
в оболочку, фактически копирует его первоначальное значение 0 в оболочку, и последующие изменения атрибута counter
функции-оболочки не будут отражены в атрибуте counter
оболочки, которыйВот почему:
from functools import wraps
def count(f):
@wraps(f)
def f1(*args):
f1.counter += 1
return f(*args)
f1.counter = 0
return f1
def memoize(f):
@wraps(f)
def f1(*args):
if not args in f1.memo:
f1.memo[args] = f(*args)
return f1.memo[args]
f1.memo = {}
return f1
@memoize
@count
def fib(n):
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
print(fib(4))
print(fib.memo)
print(fib.counter)
неправильно выводит:
3
{(1,): 1, (0,): 0, (2,): 1, (3,): 2, (4,): 3}
0
Чтобы исправить это, вы должны инициализировать counter
с изменяемым объектом.Поскольку Python изначально не имеет изменяемого целого числа, вы можете создать собственный класс, который вместо этого будет заключен в целое число:
class Int:
def __init__(self, value=0):
self.value = value
def count(f):
@wraps(f)
def f1(*args):
f1.counter.value += 1
return f(*args)
f1.counter = Int()
return f1
, чтобы:
print(fib(4))
print(fib.memo)
print(fib.counter.value)
правильно выводил:
3
{(1,): 1, (0,): 0, (2,): 1, (3,): 2, (4,): 3}
5