#python #list #function #recursion #memoization
#python #Список #функция #рекурсия #запоминание
Вопрос:
Я хочу повысить производительность рекурсивного вычисления значений
n = 100
def T(n,k):
q = 0
if n == 0 and k == 0:
return(1)
q = 1
if k>n or n<0:
return(0)
q = 1
if q != 1:
return(T(n-1,k-1) n*T(n-1,k))
for i in range(n):
for n in range(i 1):
print(T(i,n))
print("*********")
Однако я нашел способы сделать это только с функциями, которые принимают только 1 аргумент, например:
def mem(f):
memory = {}
def inner_function(x):
if x not in memory:
memory[x] = f(x)
return memory[x]
else:
return memory[x]
return inner_function
@mem
def fibonacci(n):
if n == 1 or n == 0:
return 1
else:
return fibonacci(n-1) fibonacci(n-2)
Я думал о создании 2d-массива, но пока не знаю (предполагая, что это возможно), как поможет идея сделать это со списками списков.
Комментарии:
1. Добро пожаловать в SO! Что именно делает эта рекурсивная функция? Однобуквенные переменные мне не очень помогают…. После двух ветвей остается мертвый код
return
. В общем, однако, если вы хотите запоминать функции с несколькими аргументами, просто добавьте больше аргументовinner_function
и хэшируйте их как кортежmemo
. Это может быть сложно, если эти аргументы являются изменяемыми или иным образом не хэшируемыми, что, похоже, здесь не так.2.
if q != 1:
также всегда верно….
Ответ №1:
Вы можете использовать functools.lru_cache
для этого
from functools import lru_cache
@lru_cache(maxsize=32)
def T(n,k):
q = 0
if n == 0 and k == 0:
return(1)
q = 1
if k>n or n<0:
return(0)
q = 1
if q != 1:
return(T(n-1,k-1) n*T(n-1,k))
Вы можете использовать этот декоратор для запоминания вызовов функций, в частности, с помощью этой функции это позволит сохранить до maxsize
самых последних вызовов.
Обратите внимание, что в данном конкретном случае подавляющее большинство времени фактически тратится на запись в консоль из-за ваших print
утверждений. Если вы удалите это (но все же оставите свой T(i,n)
вызов), ваш код завершится почти мгновенно.
Комментарии:
1. совет: используйте изменяемые аргументы по умолчанию для создания функций с сохранением состояния, которые затем могут эффективно кэшироваться. На самом деле не профессионал-совет Никогда этого не делает.
2. Вы также можете использовать
@cache
, чтобы сделать кеш неограниченным.
Ответ №2:
Вы можете легко расширить свой mem
декоратор для работы с переменными *args
параметрами, просмотрев их в memory
. Это тоже будет работать **kwargs
, но вам придется преобразовать их в хэшируемый тип, например frozenset
. of tuples
. И, конечно, для этого все параметры должны быть хешируемыми.
def mem(f):
memory = {}
def inner_function(*args):
if args not in memory:
memory[args] = f(*args)
return memory[args]
return inner_function
Протестировано с вашей T
функцией, работает нормально. Однако на практике вы все равно можете захотеть использовать functools.lru_cache
.
Комментарии:
1. @Barmar Вы правы, я почему-то предположил, что это список, и не проверял.