首页 > 解决方案 > 获取装饰器的可变关键字参数的值

问题描述

我有以下代码,其中我只是有一个用于缓存函数结果的装饰器,作为具体实现,我使用了 Fibonacci 函数。

在玩弄了代码之后,我想打印在包装器cache中启动的变量。cache(这不是因为我怀疑缓存可能有问题,我只是想知道如何在不进入调试模式的情况下访问它并在装饰器中放置断点)

我试图fib_w_cache在调试模式下探索该功能,这实际上应该是 Wrapped fib_w_cache,但没有成功。

import timeit


def cache(f, cache = dict()):

    def args_to_str(*args, **kwargs):
        return str(args) + str(kwargs)

    def wrapper(*args, **kwargs):
        args_str = args_to_str(*args, **kwargs)
        if args_str in cache:
            #print("cache used for: %s" % args_str)
            return cache[args_str]
        else:
            val = f(*args, **kwargs)
            cache[args_str] = val
            return val
    return wrapper


@cache
def fib_w_cache(n):
    if n == 0: return 0
    elif n == 1: return 1
    else:
        return fib_w_cache(n-2) + fib_w_cache(n-1)


def fib_wo_cache(n):
    if n == 0: return 0
    elif n == 1: return 1
    else:
        return fib_wo_cache(n-1) + fib_wo_cache(n-2)


print(timeit.timeit('[fib_wo_cache(i) for i in range(0,30)]', globals=globals(), number=1))
print(timeit.timeit('[fib_w_cache(i) for i in range(0,30)]', globals=globals(), number=1))

标签: pythonpython-3.xdecoratorpython-decorators

解决方案


我承认这在某种意义上不是一个“优雅”的解决方案,但请记住,python 函数也是对象。因此,对您的代码稍作修改后,我设法将缓存作为修饰函数的属性注入:

import timeit


def cache(f):

    def args_to_str(*args, **kwargs):
        return str(args) + str(kwargs)

    def wrapper(*args, **kwargs):
        args_str = args_to_str(*args, **kwargs)
        if args_str in wrapper._cache:
            #print("cache used for: %s" % args_str)
            return wrapper._cache[args_str]
        else:
            val = f(*args, **kwargs)
            wrapper._cache[args_str] = val
            return val
    wrapper._cache = {}
    return wrapper


@cache
def fib_w_cache(n):
    if n == 0: return 0
    elif n == 1: return 1
    else:
        return fib_w_cache(n-2) + fib_w_cache(n-1)

@cache
def fib_w_cache_1(n):
    if n == 0: return 0
    elif n == 1: return 1
    else:
        return fib_w_cache(n-2) + fib_w_cache(n-1)


def fib_wo_cache(n):
    if n == 0: return 0
    elif n == 1: return 1
    else:
        return fib_wo_cache(n-1) + fib_wo_cache(n-2)

print(timeit.timeit('[fib_wo_cache(i) for i in range(0,30)]', globals=globals(), number=1))
print(timeit.timeit('[fib_w_cache(i) for i in range(0,30)]', globals=globals(), number=1))
print(fib_w_cache._cache)
print(fib_w_cache_1._cache) # to prove that caches are different instances for different functions

推荐阅读