python - 如果装饰器更改了 API,我应该如何处理装饰函数的文档字符串?

标签 python api decorator docstring

背景

我有一个库,其中包含多个读取或写入文件的函数。每个函数都接受文件作为第一个参数,可以是文件对象,也可以是文件名。因此,所有函数在开头都有相同的代码,类似于以下内容:

if isinstance(f, str):
    file_obj = open(f, 'w')
else:
    file_obj = f

现在我想我可以在装饰器中编写一次并将所有函数包装在其中,而不是重复自己。 (我还在考虑在同一个装饰器中实现上下文管理器接口(interface)。)

所以如果我这样做,函数将如下所示:

@file_aware('w')
def function(f, *args, **kwargs):
    """Do stuff. `f` can be file object or file name"""
    for line in f:
       ....

问题

我担心的是,现在该函数的文档字符串与其下面的代码不对应。 (我计划使用 functools.wraps 保留装饰函数的文档字符串。) 它是否降低了代码的可读性/可维护性/透明度? 据我了解,装饰器可以轻松地来来去去,但与此同时,这有点改变了 API(我不打算删除该功能)。对于这种情况,“最佳实践”方法是什么?

我可以考虑在装饰器内自动处理文档字符串,但是:

  • 这不是最自然的事情;
  • 这只对在线文档有意义,对阅读源代码的人没有帮助(相反,相反)。

最佳答案

一种选择是将文档字符串传递到装饰器中。这样,您仍然可以通过函数定义获得用于读取源代码的文档字符串,但如果您要更改或删除装饰器,则不会最终得到不正确的文档字符串。

例如:

@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

关于python - 如果装饰器更改了 API,我应该如何处理装饰函数的文档字符串?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13938230/

相关文章:

python - 将列添加到 Pandas 数据框时如何避免列和 DatetimeIndex 之间的混淆

c++ - E_FAIL or S_FALSE,哪个更适合表示没有这个属性?

spring - CommandLineRunner 需要一个无法找到的 bean

api - PayPal 开发者账户和 API ..如果账户受限会怎样?

python - 如何在python 3中正确使用@property装饰器?

python - 如何在 ubuntu 上使用 python 创建自动运行文件?

python - 通过列表理解修改属性

Python argparse,运行一个或多个子命令

java - 验证 Java 中装饰器模式的实现

python - 为什么 Python 装饰器而不是闭包?