** wargs是反模式吗?


16

我们内部代码库中有很多代码在内部调用我们的库-这些库通常有很多参数(例如matplotlib),我们的代码通常仅执行特定任务,然后将其传递**kwargs给下一个调用的函数。

例如:

def our_method(dataframe, **kwargs):
    result = do_something_with_data(dataframe)
    external_module.draw(result, **kwargs)

虽然**kwargs阻止了我们重复方法声明中的所有参数,但是这也使得在调用时哪些参数有效是非常不透明的our_method-我必须知道调用哪个方法,而我通常不希望知道。

你对此有什么看法?

Answers:


16

开发人员如何使用您的代码?换句话说,它们究竟是做什么工作来确定应使用哪些参数以及如何使用?

  • 如果他们依靠从您的代码自动生成的文档,并且生成器不知道如何处理**kwargs,这确实是有问题的。除了在文档中找到参数列表及其含义之外,它们几乎没有任何信息,只是模糊的“需要一些参数”。

    通过手动记录该方法,替换自动生成的文档,可能可以解决此问题。这需要方法的实现者进行额外的工作,但是请记住,代码(及其文档)的读取频率要比其编写的频率高得多。

  • 如果代码是他们的文档,则使用方法的开发人员还**kwargs需要两个额外的步骤:他们不仅需要查看该方法的签名,还需要查看其实际实现,以查找它实际调用的其他方法。然后,他们需要使用另一种方法来最终找到他们想要的东西。

    这并不需要很多努力,但是仍然应该一次又一次地重复这些努力。最糟糕的是,您无法通过添加文档来帮助他们:如果您注释方法,列出实际参数,则存在很大的风险,即方法调用的库的下一版本将具有不同的参数,并且文档将已经过时了,因为没有人会记得它需要保持最新。

我的建议是**kwargs仅依赖范围缩小的方法。_例如,在类中很少使用的私有方法(在Python上下文中,私有方法是指以开头的方法)是不错的选择。另一方面,在整个代码库中被数十个类使用的方法是非常不好的选择。

毕竟,在编写的方法中重写您调用的方法的参数时,无需花费太多精力。希望大多数方法的参数不要超过6到8个,如果是,请问问自己是否不应重构代码。在所有情况下:

  • 在您的方法中明确显示参数不需要很多工作,

  • 稍后,您可能仍希望验证参数(尽管如果仅依靠这一点来使参数明确,则会违反YAGNI)。


我真的很喜欢这个答案,并认为这是一个很好的答案。不幸的是,我们的许多代码都使用这种模式有许多公共方法。但是现在我有一个论点,我们应该更改它(并删除matplotlib,从未见过更烂的“接口”。)
Christian Sauer

3

如果下一级函数具有__doc__,则只需将__doc__复制到新函数即可。

例如:

def a(x):
    """This function takes one parameter, x, and does nothing with it!"""
    pass

def b(**kwargs):
    a(**kwargs)

b.__doc__=a.__doc__

这可以递归应用,也可以由装饰器应用(如果您无论如何批量进行此操作都可能有用)。__doc__字符串也可以进行操作,以在末尾添加更多内容。这意味着所显示的参数仍将是kwargs,但至少在帮助中有描述实际参数的文档。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.