调用内部/装饰函数时,可以将参数传递给装饰器函数吗?

时间:2020-09-29 15:22:11

标签: python decorator

希望该术语是正确的。我有这个装饰器功能,可以读取文本文件:

def read_commands(inner, path=BATCH_PATH):
    with open(path) as f:
        commands = ['python ' + line.replace('\n', '') for line in f]

    def wrapper(*args, **kwargs):
        for command in commands:
            inner(command, *args, **kwargs)

    return wrapper

这是它装饰的功能之一:

@read_commands
def execute_multi_commands(command, count):
    LOG.info(f'Executing command {count}: {command}')
    os.system(command)
    count += 1

我希望能够在调用execute_multi_commands时更改默认路径,就像在我的main中一样:

def main():
    parser = argparse.ArgumentParser()

    parser.add_argument('-b', '--batch', action='store', type=str, dest='batch')
    args = parser.parse_args()
    
    count = 1
    execute_multi_commands(count, path=args.batch)

但是,显然path不是execute_multi_commands中的参数,因此无法正常工作。当我调用path时,是否可以将read_commands传递给装饰器函数execute_multi_commands? -或更可能是功能上等效的替代品?

1 个答案:

答案 0 :(得分:1)

您不能,至少不能使用装饰器的编写方式。装饰一个函数时,它类似于:

def execute_multi_commands(command, count):
    LOG.info(f'Executing command {count}: {command}')
    os.system(command)
    count += 1

execute_multi_commands = read_commands(execute_multi_commands)

因此,在此之后,read_commands已被执行,并且文件已被读取。

您可以做的是更改装饰器以读取包装中的文件,例如:

def read_commands(inner, path=BATCH_PATH):

    def wrapper(*args, **kwargs):

        if "path" in kwargs:
            path_ = kwargs.pop("path")
        else:
            path_ = path

        with open(path_) as f:
            commands = ['python ' + line.replace('\n', '') for line in f]

        for command in commands:
            inner(command, *args, **kwargs)

    return wrapper

...但是这意味着每次您调用修饰后的函数时都读取文件,这与您之前所做的稍有不同。