使用装饰器会在已定义的函数上产生NameError

时间:2015-08-26 14:45:00

标签: python python-decorators

为什么这样:

def fn(proc, *args, **kwargs):
    cache = proc.cache = {}
    def cached_execution(cache, *args, **kwargs):
        if proc in cache:
            if args in cache[proc]:
                return cache[proc][args]
        res = proc(args)
        cache[proc] = {args: res}
        return res
    return cached_execution(cache, proc, *args, **kwargs)

@fn
def cached_fibo(n):
    if n == 1 or n == 0:
        return n
    else:
        return cached_fibo(n-1) + cached_fibo(n-2)

print cached_fibo(100)

抛出这样的例外:

  

NameError:未定义全局名称“cached_fibo”

我错过了什么基本概念?

(从概念上讲,**kwargs仅用于装饰。不用于检索缓存结果,但不用担心它。)

2 个答案:

答案 0 :(得分:3)

装饰器应该返回一个函数,而不是调用函数的结果。 但是这导致我们犯下一个错误:当你将cacheproc传递给cached_execution函数时,它们会落在*args中,然后传递给proc }。这没有意义。只需在内部方法中捕获cacheproc

def fn(proc, *args, **kwargs):
    cache = proc.cache = {}
    def cached_execution(*args, **kwargs):
        if proc in cache:
            if args in cache[proc]:
                return cache[proc][args]
        res = proc(*args)
        cache[proc] = {args: res}
        return res
    return cached_execution

另一个问题:你没有解包args。您应该拨打proc(*args)而不是proc(args)(已在上面修复过)。

答案 1 :(得分:1)

包装器似乎有点格格不入。这是一个更新版本:

def fn(proc):
    cache = proc.cache = {}

    def cached_execution(*args, **kwargs):
        if proc in cache:
            if args in cache[proc]:
                return cache[proc][args]
        res = proc(args[0])
        cache[proc] = {args: res}
        return res
    return cached_execution

您试图在包装器中运行包装器函数,而不是将其返回以作为函数运行,从而导致问题。

下一个问题是,当您只想要第一个时,您提供的参数是*args的元组proc(args)列表,因此需要转换为proc(args[0])