让我们说,我正在使用argparse
模块,如果某个标志为True
,我希望修饰一些函数,并返回未修饰的函数(如果它是&#39}假的。
有可能吗?
当然,我可以制作一些函数,并在标志为True
时使用其中一个,而在False
时使用另一个函数,但它不是我的标准。寻找。
答案 0 :(得分:2)
这不是一个很好的方法,因为在任何参数解析完成之前,模块中的函数通常已经定义了。如果你想让它工作,你必须延迟函数定义,直到argparse完成它之后。
你可能会忽略的关键是装饰是在功能定义时完成的,即它在导入时发生一次。而且,通常,我们将所有导入放在模块的顶部(样式指南也建议这样做)。
这并不意味着你的想法是不可能的, 是可能的,但这意味着你必须在定义这个函数之前解析命令行参数,这可能会或者可能没有装饰。
让我们看看实际上是什么样的:
from argparse import ArgumentParser
def maybe_decorate(condition):
def the_decorator(func):
def wrapped():
return func().upper()
if condition:
return wrapped
else:
return func
return the_decorator
the_condition = False # have to provide a default value for import
if __name__ == '__main__':
parser = ArgumentParser()
parser.add_argument('--upper', action='store_true')
args = parser.parse_args()
the_condition = args.upper
@maybe_decorate(condition=the_condition)
def foo():
return 'hello world'
if __name__ == '__main__':
print(foo())
这是我能得到的最干净的,我还有两个if __name__ == '__main__'
块。这不是一个好的风格:
sys.modules
中取出模块并重新导入它(也可能,但是很难)。 总之,条件应用的装饰器对装饰器来说不是一个好的用例。语言的惯例使得这个想法难以实现。我建议你放弃这种方法,并考虑不同的设计。
答案 1 :(得分:1)
当然,这是可能的。装饰器只是一个函数,因此您可以使装饰器的行为以某个变量为条件,就像其他任何变量一样。例如:
import argparse
flag = False
def conditional_decorator(func):
def wrapper():
res = func()
if flag:
res = res.replace('hello', 'goodbye')
return res
return wrapper
def parse_args():
p = argparse.ArgumentParser()
p.add_argument('--flag', action='store_true')
return p.parse_args()
@conditional_decorator
def myfunc():
return 'hello world'
def main():
global flag
args = parse_args()
flag = args.flag
print myfunc()
if __name__ == '__main__':
main()
使用标记调用它并打印hello world
。使用--flag
进行调用,然后打印goodbye world
。
正如其他人在评论中所说,可能有更好的方法来完成这类事情。