我有一个包含多个读取或写入文件的函数的库。每个函数都接受该文件作为第一个参数,作为文件对象或文件名。因此,所有函数在开头都具有相同的代码段,类似于以下内容:
if isinstance(f, str):
file_obj = open(f, 'w')
else:
file_obj = f
现在我想我可以在装饰器中编写一次并将所有函数包装在其中,而不是重复自己。 (我也在考虑在同一个装饰器中实现上下文管理器接口。)
因此,如果我这样做,函数将如下所示:
@file_aware('w')
def function(f, *args, **kwargs):
"""Do stuff. `f` can be file object or file name"""
for line in f:
....
我担心的是现在函数的docstring与它下面的代码不对应。
(我打算用functools.wraps
保留装饰函数的docstring。)
它是否会降低代码的可读性/可维护性/透明度?
根据我的理解,装饰器可以很容易地来去,但同时这一种改变了API(我不打算删除功能)。这种情况的“最佳实践”方式是什么?
我可以考虑在装饰器内自动处理docstring,但是:
答案 0 :(得分:3)
一种选择是将docstring传递给装饰器。这样你就可以通过函数定义获得一个用于读取源代码的文档字符串,但如果你要更改或删除装饰器,你最终会得到一个不正确的文档字符串。
例如:
@file_aware(docstring="Do stuff. `f` can be file object or file name", mode="r")
def function(f, *args, **kwargs):
for line in f:
....
您的file_aware
装饰器可能看起来像这样:
def file_aware(docstring, mode):
def deco(func):
@functools.wraps(func)
def wrapped(f, *args, **kwargs):
if isinstance(f, str):
file_obj = open(f, mode)
else:
file_obj = f
return func(file_obj, *args, **kwargs)
wrapped.__doc__ = docstring
return wrapped
return deco