将输入函数传递给多个类装饰器

时间:2018-08-18 17:14:14

标签: python python-2.7 decorator python-decorators memoization

我有一个计时器装饰器,在屏幕上打印“记忆装饰”功能所用的时间。但是,装饰器打印语句将备忘类作为功能名称打印在屏幕上,而不是输入要备忘的功能。例如,使用以下代码:

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))

返回以下内容:

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

当我想要该记忆时。该记忆为pass_and_square_time。我尝试了self.__wrapper__functools.wrapsfunctools.update_wrapper()的各种不同组合,都无济于事。

我的Timer类的实现如下:

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
    '''

我的Memoize类的实现如下:

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)

2 个答案:

答案 0 :(得分:0)

使用闭包比使用类要简单得多。

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 _                

我也将timer写为

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 _

然后

 @timer
 @memoize
 def pass_and_square_time(seconds):
     time.sleep(seconds)
     return seconds**2

答案 1 :(得分:0)

RoundDownpublic static int RoundDown(this double dbl) { return Convert.ToInt32(Math.Floor(dbl)); } 都被实现为类,以这样的方式在装饰函数时它们返回自己的类的实例。因此,不能在返回的函数上使用Timer或设置Memoize(因为没有返回的函数)。

相反,我建议在functools.wrap__name__上实现__repr__,这将更好地表示修饰后的功能。当需要获取对象的字符串表示形式时,Python解释器将调用该函数。

这是当前情况和问题:

Timer

现在,如果您添加到Memoize,则:

def pass_and_square_time(seconds):
    time.sleep(seconds)
    return seconds**2

print(pass_and_square_time)         # <function pass_and_square_time at 0x00000000029A1620>
print(Memoize(pass_and_square_time))  # <Memoize object at 0x000000000295BDA0>

然后按预期工作:

Memoize

然后对class Memoize(object): ... def __repr__(self): return repr(self._fcn) 执行相同的操作,即使这样也可以:

print(pass_and_square_time)         # <function pass_and_square_time at 0x00000000029A1620>
print(Memoize(pass_and_square_time))  # <function pass_and_square_time at 0x00000000029A1620>

请注意,Memoize正是装饰者在这里所做的:

print(Timer(Memoize(pass_and_square_time)))  # <function pass_and_square_time at 0x00000000029A1620>