Мемоизация и отслеживание функций - PullRequest
2 голосов
/ 04 февраля 2020

Я пытаюсь отследить, сколько раз запускается функция, а также использовать напоминания, чтобы избежать ненужного запуска функции. Я не могу понять, почему, но кажется, что в памятке хранятся два одинаковых значения для большинства значений.

def track(f):
  def wrapper(arg):
    wrapper.count += 1
    print(arg)
    return f(arg)
  wrapper.count = 0
  return wrapper

def memoize(f):
    memo = {}
    def wrapper(arg):
        if arg not in memo:            
            memo[arg] = f(arg)
        return memo[arg]
    return wrapper

@track
@memoize
def fib(n):
  return n if n in (0,1) else fib(n-1) + fib(n-2)

print('Result:', fib(10), '\nCount:', fib.count)

Результаты должны выглядеть следующим образом:

10
9
8
7
6
5
4
3
2
1
0
Result: 55
Count: 11

По какой-то причине он выделяет двойное число для всего, что меньше 9. Счет фактически возвращается 19. Любая помощь будет с благодарностью.

1 Ответ

1 голос
/ 04 февраля 2020

Вам необходимо переместить memoize в track:

def track(f):
  @memoize
  def wrapper(arg):
    wrapper.count += 1
    print(arg, end=' ')
    return f(arg)
  wrapper.count = 0
  return wrapper

def memoize(f):
    memo = {}
    def wrapper(arg):
        if arg not in memo:            
            memo[arg] = f(arg)
        return memo[arg]
    return wrapper

@track
def fib(n):
    return n if n in (0,1) else fib(n-1) + fib(n-2)

print('Result:', fib(10), '\nCount:', fib.count)
10 9 8 7 6 5 4 3 2 1 0 Result: 55 
Count: 11

Добавив дополнительный аргумент к track, вы можете контролировать, хотите ли вы использовать memoize декоратор. В этом случае вы должны использовать functools.wraps:

from functools import wraps

def track(is_memoized):
  def dec(f):
    def wrapper(arg):
      wrapper.count += 1
      print(arg, end=' ')
      return f(arg)
    wrapper.count = 0
    if is_memoized:
      wrapper = memoize(wrapper)
    return wrapper
  return dec

def memoize(f):
    memo = {}
    @wraps(f)
    def wrapper(arg):
        if arg not in memo:            
            memo[arg] = f(arg)
        return memo[arg]
    return wrapper


@track(is_memoized=True)
def fib(n):
    return n if n in (0,1) else fib(n-1) + fib(n-2)

print('Result:', fib(10), '\nCount:', fib.count)
10 9 8 7 6 5 4 3 2 1 0 Result: 55 
Count: 11

@track(is_memoized=False)
def fib(n):
    return n if n in (0,1) else fib(n-1) + fib(n-2)

print('Result:', fib(5), '\nCount:', fib.count)
5 4 3 2 1 0 1 2 1 0 3 2 1 0 1 Result: 5 
Count: 15
...