哪种是根据通过命令行传递的条件来装饰函数的pythonic方法?

时间:2017-09-12 23:06:08

标签: python

让我们说,我正在使用argparse模块,如果某个标志为True,我希望修饰一些函数,并返回未修饰的函数(如果它是&#39}假的。

有可能吗? 当然,我可以制作一些函数,并在标志为True时使用其中一个,而在False时使用另一个函数,但它不是我的标准。寻找。

2 个答案:

答案 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__'块。这不是一个好的风格:

  • 看起来很奇怪,阅读代码的任何其他人都会说" wtf"。
  • 难以编写测试。要测试两个分支,您必须从sys.modules中取出模块并重新导入它(也可能,但是很难)。
  • 重构时,您可能无法在不改变函数行为的情况下在模块中移动函数定义。这违反了最不惊讶的原则。
  • 如果稍后再回到此代码,您也可能会说" dude, wtf"。

总之,条件应用的装饰器对装饰器来说不是一个好的用例。语言的惯例使得这个想法难以实现。我建议你放弃这种方法,并考虑不同的设计。

答案 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

正如其他人在评论中所说,可能有更好的方法来完成这类事情。