【问题标题】:decorating recursive functions装饰递归函数
【发布时间】:2011-05-02 17:27:10
【问题描述】:

我有一个我写的装饰器,它将为给定的函数计时。它似乎适用于任何函数,除了递归函数。

装饰者:

def tictoc(repeats=3, loops=1):
    def t(func):
        from functools import partial, wraps
        import timeit
        @wraps(func)
        def timer(*args, **kargs):
            elapsed = timeit.repeat(partial(func, *args, **kargs), repeat = repeats, number=loops)
            mine = min(elapsed)
            print "%s finished in %.5fs (%d loops, %d times) with %.5fs per loop" % (func.__name__, mine, loops, repeats, mine/loops)
        return timer
    return t

递归函数是基本的斐波那契算法。

@tictoc()
def fib(i):
    return ( 0 if i == 0 else
             1 if i == 1 else
             fib(i-1) + fib(i-2) )
fib(15)

程序失败并出现以下错误

fib finished in 0.00000s (1 loops, 3 times) with 0.00000s per loop
fib finished in 0.00000s (1 loops, 3 times) with 0.00000s per loop
fib finished in 0.00000s (1 loops, 3 times) with 0.00000s per loop
Traceback (most recent call last):
  File "decor.py", line 61, in <module>
    [fib(x) for x in range(1,50)]
  File "/home/grout/Dropbox/Python/tictoc.py", line 7, in timer
    elapsed = timeit.repeat(partial(func, *args, **kargs), repeat = repeats, number=loops)
  File "/usr/lib/python2.7/timeit.py", line 233, in repeat
    return Timer(stmt, setup, timer).repeat(repeat, number)
  File "/usr/lib/python2.7/timeit.py", line 221, in repeat
    t = self.timeit(number)
  File "/usr/lib/python2.7/timeit.py", line 194, in timeit
    timing = self.inner(it, self.timer)
  File "/usr/lib/python2.7/timeit.py", line 100, in inner
    _func()
  File "decor.py", line 59, in fib
    fib(i-1) + fib(i-2) )
TypeError: unsupported operand type(s) for +: 'NoneType' and 'NoneType'

我不明白的是装饰器如何执行几次然后失败。任何帮助将不胜感激。

【问题讨论】:

    标签: python decorator


    【解决方案1】:

    装饰器返回的函数不返回任何内容。因此,虽然fib 应该返回一个整数,但您包装的fib 返回None。它工作了几次,因为在没有检查 fib 的结果的情况下进行了一些递归调用,但是当它需要结果时(当它必须将其中两个加在一起时)你会得到异常。

    【讨论】:

    • 感谢您指出这一点。但是,我遇到了另一个问题。装饰器现在对每个单独的函数调用计时并将结果打印到标准输出。我宁愿每次通话都静默计时并返回累积时间。但是,我不知道如何实现这一点。有什么建议吗?
    • 我认为将每个运行时添加到列表中(timeit.repeats 返回一个列表),然后返回 min(min(cumulative_times)) 将是这样做的方法。
    • 只需执行以下操作:“start=time.time(); for i in xrange(repeat): func(*args,**kwargs); time_taken=time.time()-start”
    【解决方案2】:

    我想我会解决这个问题

    def tictoc(func, repeats=3, loops=100, *args, **kargs):
        elapsed = timeit.repeat(lambda: func(*args, **kargs), repeat = repeats, number = loops)
        mine = min(elapsed)
        return "%s finished in %.5fs (%s loops, repeated %s times): %.5fs best time per loop"         %(func.__name__, mine, loops, repeats, mine/loops)
    

    【讨论】:

      猜你喜欢
      • 2022-01-01
      • 2020-05-20
      • 2012-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多