将命令行参数传递给调用带有装饰器参数的装饰函数的函数

Posted

技术标签:

【中文标题】将命令行参数传递给调用带有装饰器参数的装饰函数的函数【英文标题】:Passing command line arguments to a function that calls a decorated function with decorator arguments 【发布时间】:2020-03-22 08:30:54 【问题描述】:

这个例子是人为的,但代表了现实生活中的情况:

    我有一个接受命令行参数的 python 脚本。

    main() 将解析参数,并将它们传递给中间函数(代码示例中的caller_func

    然后中间函数将调用一个装饰函数(示例中为fib()),该函数使用functools 中的lru_cache 进行装饰,并且缓存的maxsize 是要接受的参数命令行并通过中间函数传递。

我该怎么做?

import argparse
from functools import lru_cache

def main():
    # boilerplate for parsing command line arguments
    parser = argparse.ArgumentParser()
    parser.add_argument("--cache_size", default="10")
    parser.add_argument("--fibo_num", default="20")
    args = parser.parse_args()
    cache_size = int(args.cache_size)
    fibo_num = int(args.fibo_num)

    caller_func(cache_size, fibo_num)

#Intermediate function that is supposed to call decorated function
def caller_func(cache_size, fib_num): 
    print(fib(fib_num))

#function decorated by LRU cache
@lru_cache(maxsize=cache_size)
def fib(n): 
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

if __name__ == "__main__":
    main()

运行方式

python3 example.py --cache_size 5 --fibo_num 30

抛出

NameError: name 'cache_size' is not defined

我尝试将cache_size 设为全局变量,但没有奏效,而且我也不想要全局变量。

【问题讨论】:

装饰器在定义时执行,甚至在调用 main 之前。 也许在这里使用部分函数:***.com/a/25827070/3279716 很好的诊断@jonrsharpe。那有什么解决办法呢?是否可以从命令行参数装饰这个装饰器? 你不必像那样应用装饰器;鉴于中间体无论如何都需要缓存大小(到目前为止是什么?)你可以调用lru_cache(maxsize=cache_size)(fib)(fibo_num) lru_cache(maxsize=cache_size)(fib)(fibo_num) 不会做你想做的事,因为它不会将函数 fib 重新分配给修饰版本;所以递归调用将在不使用缓存的未修饰的fib 函数上。 【参考方案1】:

你没有使用带有装饰器语法的装饰器。您可以等待“装饰”fib,直到获得所需的缓存大小。例如,

import argparse
from functools import lru_cache

def main():
    global fib
    # boilerplate for parsing command line arguments
    parser = argparse.ArgumentParser()
    parser.add_argument("--cache_size", default="10")
    parser.add_argument("--fibo_num", default="20")
    args = parser.parse_args()
    cache_size = int(args.cache_size)
    fibo_num = int(args.fibo_num)

    fib = lru_cache(maxsize=cache_size)(fib)

    caller_func(fibo_num)

#Intermediate function that is supposed to call decorated function
def caller_func(fib_num): 
    print(fib(fib_num))

def fib(n): 
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

if __name__ == "__main__":
    main()

【讨论】:

以上是关于将命令行参数传递给调用带有装饰器参数的装饰函数的函数的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 中,如何获取带参数传递给装饰器的函数名称?

如何将非硬编码参数传递给 Python 装饰器?

将参数传递给要装饰的类方法的装饰器

将参数传递给 decontext 装饰器

将附加参数传递给角度组件内的方法装饰器

Django - 将参数传递给 CBV 装饰器的正确方法?