【问题标题】:Python 2.7 - Using Classes as Decorators for Timing and MemoizationPython 2.7 - 使用类作为时间和记忆的装饰器
【发布时间】:2019-01-24 21:54:48
【问题描述】:

我是 Python 的新手,我目前正在做一个项目,我有一个 Timer 和 Memoize 类,它们都应该能够用作装饰器,并且可以使用具有任意数量参数的函数.

问题

我目前的问题是我试图将它们都用作函数的装饰器;但是,Timer 仅在第一次调用函数时调用,而不是第二次调用。例如,使用以下代码:

# Import the Memoize class from the memoization module
from memoization import Memoize


# Import the time module
import time


# Import the logging module
import logging


# Import the Timer class from the timer module
from timer import Timer


@Memoize
@Timer
def pass_and_square_time(seconds):
    # Call time.sleep(seconds)
    time.sleep(seconds)
    # Return the square of the input seconds amount.
    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):

<function pass_and_square_time at 0x02B9A870> 30.003000021 seconds

    The initial call of pass_and_square_time(30) yields: 900

    The second call of pass_and_square_time(30) yields: 900

当我希望它也返回第二次调用之上的秒数时(因为那是第二次的时间。初始调用之上的时间是初始调用的时间)。我相信@Memoize 装饰器在第二次调用时工作正常,因为它最初在第一次调用之后出现,而不是执行 time.sleep(30) 调用。


定时器

我的 Timer 类实现如下:

class Timer(object):
    def __init__(self, fcn, timer_name='Timer'):
        self._start_time = None
        self._last_timer_result = None
        self._display = 'seconds'
        self._fcn = fcn
        self._timer_name = timer_name
        self.__wrapped__ = self._fcn

    def __call__(self, *args):
        self.start()
        fcn_res = self._fcn(*args)
        self.end()
        print '\n{func} {time} seconds'.format(func=self._fcn, time=self.last_timer_result)
        return fcn_res

    '''
    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 类实现如下:

class Memoize(object):
    def __init__(self, fcn):
        self._fcn = fcn
        self._memo = {}
    self.__wrapped__ = self.__call__

def __call__(self, *args):
    if args not in self._memo:
        self._memo[args] = self._fcn(*args)

    return self._memo[args]

使用的参考文献

我查看并尝试模拟我的课程的参考资料是:

Python 类装饰器

Python 记忆


感谢您的阅读和您能提供的任何帮助!

【问题讨论】:

  • Memoize 正在做它应该做的事情:它使用给定的参数返回上次调用的缓存值,而不是再次调用(定时)函数。
  • 但是有没有一种方法可以让我调用计时器,无论 memoize 返回缓存值还是调用函数 @chepner ?基本上,我想表明 memoize 中的缓存值允许 pass_and_square_time() 函数在第二次调用时使用 Timer 装饰更快地返回值,如果这有意义的话。
  • 那么你需要显式地对记忆函数计时,而不是记忆一个计时函数。 (这可能很简单,就像交换两个装饰器的顺序一样;我还没有测试过。)
  • 交换两个装饰器的顺序有效!!我以为我之前尝试过但无济于事,但我想我后来对代码的编辑之一可能已经修复了它。感谢@chepner 对愚蠢问题的帮助

标签: python-2.7 decorator python-decorators memoization


【解决方案1】:

使用您的代码,您正在记忆一个定时函数,这意味着当在缓存中找到参数时也会跳过定时代​​码。如果你颠倒装饰器的顺序

@Timer
@Memoize
def pass_and_square_time(seconds):
    # Call time.sleep(seconds)
    time.sleep(seconds)
    # Return the square of the input seconds amount.
    return seconds**2

现在你正在计时一个记忆函数。无论参数是否在缓存中找到,您都可以为调用 memoized 函数计时。

【讨论】:

  • 交换装饰器的一个问题是 Timer 在它的 time elapsed print 语句中打印 Memorize 函数名称,而不是 pass_and_square_time 函数名称。关于如何解决@chepner 的任何建议?再次感谢!
  • 查看functools模块;有一个装饰器可以用来保存原始函数的元数据 (wraps?wrapped?)
  • 我尝试了 wraps,但我认为我需要在 memoize 函数中返回一个包装函数才能使其工作,因为它是一个装饰器 @chepner。
猜你喜欢
  • 1970-01-01
  • 2021-07-16
  • 2014-03-15
  • 1970-01-01
  • 2011-03-02
  • 2011-05-24
  • 2012-04-18
  • 1970-01-01
  • 2020-09-01
相关资源
最近更新 更多