改变签名的装饰器是不好的模式吗?

时间:2018-08-15 11:26:19

标签: python

我有多种形式的函数:

def parse_file_1(file_name)
    # do something generic
    with open(file_name) as f:
        for line in f:
            # do some generic things with line
            # do some things specific to parse_file_1 with line

为避免重复大量代码,我使用装饰器将其重写:

def parse_file(parse_function):
     def _parse_file(file_name):
         # do something generic
         with open(file_name) as f:
             for line in f:
                 # do some generic things with line
                 parse_function(line)
     return _parse_file

@parse_file
def parse_file_1(line):
    # do some things specific to parse_file_1 with line

这完全可以正常工作-这两个版本在功能上如预期的一样,并且很容易编写这种形式的新功能而无需复制和粘贴通用代码。

但是,装饰器parse_file更改了parse_file_1的签名,这混淆了PyCharm(它认为parse_file_1具有签名(line)而不是(file_name)),并且通常,很难确定parse_file_1的签名。

这是多么糟糕的做法,以及(如果不好的话)有什么好的选择(理想情况下不需要太多重复的代码)?另外,让PyCharm知道parse_file_1的真实签名的方法可以消除我目前遇到的最大问题。

1 个答案:

答案 0 :(得分:3)

我不会为此使用装饰器。相反,将解析器函数传递给的高阶生成器怎么样?

def parse_using(file_name, func):
    with open(file_name) as f:
        for line in f:
            yield func(line)

def parse_foo_line(line):
    return 'This line is very foo-ey: ' + line

parsed_foo = parse_using('foo.txt', parse_foo_line)
parsed_bar = parse_using('bar.txt', parse_bar_line)  # etc...

请注意,这些函数是生成器,因此它们在迭代之前不会真正解析任何内容(即使那样,它们仅返回一次结果)。如果您想热切分析内容,请投射到列表中。

parsed_foo = list(parse_using('foo.txt', parse_foo_line))