I have a Timer decorator printing the time elapsed for a Memoize decorated function on screen. However, the decorator print statement prints the memoize class as the function name on screen rather than the function input to memoize. For instance, using this code:
from memoization import Memoize
import time
import logging
from timer import Timer
@Timer
@Memoize
def pass_and_square_time(seconds):
time.sleep(seconds)
return seconds**2
def main():
logging.getLogger().setLevel(logging.ERROR)
print '\nFor pass_and_square_time({30}):'.format(n=num)
print '\n\tThe initial call of pass_and_square_time(30) yields: {ret}'.format(ret=pass_and_square_time(30))
print '\n\tThe second call of pass_and_square_time(30) yields: {ret}'.format(ret=pass_and_square_time(30))
returns the following:
For pass_and_square_time(30):
Timer Time Elapsed: 30.0 seconds
<memoization.Memoize object at 0x02E5BBD0> 30.0 seconds
The initial call of pass_and_square_time(30) yields: 900
Timer Time Elapsed: 0.0 seconds
<memoization.Memoize object at 0x02E5BBD0> 0.0 seconds
The second call of pass_and_square_time(30) yields: 900
when I want that memoization.Memoize to be pass_and_square_time
. I've tried a variety of different combinations of self.__wrapper__
, functools.wraps
, and functools.update_wrapper()
to no avail.
My Timer class is implemented as follows:
class Timer(object):
def __init__(self, fcn=None, timer_name='Timer'):
self._start_time = None
self._last_timer_result = None
self._display = 'seconds'
self._fcn = fcn
self._timer_name = timer_name
def __call__(self, *args):
self.start()
fcn_res = self._fcn(*args)
self.end()
print '\n\t{func} {time} seconds'.format(func=self._fcn, time=self.last_timer_result)
return fcn_res
def __get__(self, obj, objtype):
return partial(self.__call__, obj)
'''
start(), end(), and last_timer_result functions/properties implemented
below in order to set the start_time, set the end_time and calculate the
last_timer_result, and return the last_timer_result. I can include more
if you need it. I didn't include it just because I didn't want to make
the post too long
'''
My Memoize class is implemented as follows:
from functools import update_wrapper, partial
class Memoize(object):
def __init__(self, fcn):
self._fcn = fcn
self._memo = {}
update_wrapper(self, fcn)
def __call__(self, *args):
if args not in self._memo:
self._memo[args] = self._fcn(*args)
return self._memo[args]
def __get__(self, obj, objtype):
return partial(self.__call__, obj)
This is a lot simpler using closures than classes.
import functools
import time
def memoize(f):
_memo = {}
@functools.wraps(f)
def _(*args):
if args not in _memo:
_memo[args] = f(*args)
return _memo[args]
return _
I would similarly write timer
as
def timer(f):
@functools.wraps(f)
def _(*args):
start = time.time()
rv = f(*args)
end = time.time()
print '\n\t{func} {t} seconds'.format(func=f.__name__, t=end - start)
return rv
return _
Then
@timer
@memoize
def pass_and_square_time(seconds):
time.sleep(seconds)
return seconds**2