Это - "хорошая практика" для создания класса как тот ниже этого, может обработать процесс memoization для Вас? Преимущества memoization являются настолько большими (в некоторых случаях, как этот, где он отбрасывает с 501 003 до вызовов функции 1507 года и с 1,409 до 0,006 секунд процессорного времени на моем компьютере), что кажется, что класс как это был бы полезен.
Однако у меня есть отрицательные комментарии только для чтения по поводу использования eval()
. Действительно ли это использование его простительно, учитывая гибкость этот подход предложения?
Это может сохранить любое возвращенное значение автоматически за счет проигрывающих побочных эффектов.Спасибо.
import cProfile
class Memoizer(object):
"""A handler for saving function results."""
def __init__(self):
self.memos = dict()
def memo(self, string):
if string in self.memos:
return self.memos[string]
else:
self.memos[string] = eval(string)
self.memo(string)
def factorial(n):
assert type(n) == int
if n == 1:
return 1
else:
return n * factorial(n-1)
# find the factorial of num
num = 500
# this many times
times = 1000
def factorialTwice():
factorial(num)
for x in xrange(0, times):
factorial(num)
return factorial(num)
def memoizedFactorial():
handler = Memoizer()
for x in xrange(0, times):
handler.memo("factorial(%d)" % num)
return handler.memo("factorial(%d)" % num)
cProfile.run('factorialTwice()')
cProfile.run('memoizedFactorial()')
Вы можете мемоизировать, не прибегая к eval
.
Мемоизатор (очень простой):
def memoized(f):
cache={}
def ret(*args):
if args in cache:
return cache[args]
else:
answer=f(*args)
cache[args]=answer
return answer
return ret
@memoized
def fibonacci(n):
if n==0 or n==1:
return 1
else:
return fibonacci(n-1)+fibonacci(n-2)
print fibonacci(100)
eval
часто неправильно пишется как зло
в первую очередь потому, что идея выполнения «строк» во время выполнения чревата соображениями безопасности. Достаточно ли вы ускользнули от кода? Кавычки? И множество других досадных головных болей. Ваш обработчик мемоизов работает, но на самом деле это не тот способ работы с Python. Подход MAK намного больше Pythonic. Попробуем несколько экспериментов.
Я отредактировал обе версии и заставил их запускаться только один раз со 100 на входе. Я также перенес экземпляр Memoizer
.
Вот результаты.
>>> timeit.timeit(memoizedFactorial,number=1000)
0.08526921272277832h
>>> timeit.timeit(foo0.mfactorial,number=1000)
0.000804901123046875
В дополнение к этому, ваша версия требует наличия оболочки вокруг функции, которая должна быть записана в виде строки. Это уродливо. Решение MAK является чистым, поскольку «процесс запоминания» заключен в отдельную функцию, которую можно удобно ненавязчиво применить к любой дорогостоящей функции. Это не очень питонично. У меня есть некоторые подробности о написании таких декораторов в моем руководстве по Python по адресу http://nibrahim.net.in/self-defence/ , если вам интересно.