首页 > 解决方案 > 使用 *args 和 **kwargs 而不是显式列出预期参数

问题描述

在处理一个有很多嵌套函数调用和对象层次结构的项目时,我想知道将所有必需参数传递到最高层并从那里逐步传递到较低层的最佳实践是什么。

示例:3 个类及其所需的(构造函数)参数:

A类:a、b

B类:c、d、e

C类:f

类 A 持有 B 的实例,B 持有 C 的实例。它们在各自父级的构造函数中初始化。所以这意味着使用我的代码的人只会初始化 A 的一个新对象,并且必须将所有参数 a、b、c、d、e、f 传递给 A,在那里它们被处理或进一步分发。

示例代码:

class A(object):
    def __init__(self, a, b, c, d, e, f):
        b = B(c, d, e, f)

class B(object):
    def __init__(self, c, d, e, f):
        c = C(f)

class C(object):
    def __init__(self, f):
        pass

我的第一次尝试是直接在构造函数中列出一个类及其所有子类需要的所有参数,但这很容易出错,而且代码冗余度也很高,尤其是在每一层都提供默认值时。所以我正在考虑改用 **kwargs 和 *args 。

这样做的好处是我可以将这些传递给孩子,每一层都可以从那里获取它需要的参数。

但是,缺点是想要使用此层次结构的类的人无法使用 IDE 的自动完成功能来查看预期的参数。

什么被认为是 Python 3 中的最佳实践?

标签: pythonargskeyword-argument

解决方案


编码不应该是满足任何 IDE 要求的手段,你在谈论not use the IDE's auto-completion to see which parameters are expected...你的代码不应该是为了让你的 IDE 快乐而编写的,相反它应该很容易被其他编码人员使用。这是什么意思?您公开的公共界面应该直观且易于人们学习,而不是 IDE。我想说好的代码满足的众多要求之一是您是否甚至不需要阅读任何文档,但公共界面是不言自明的。

这是一个有趣的编程报价供您考虑:

函数的理想参数数量为零(niladic)。接下来是一个(单子),紧随其后的是两个(二元)。应尽可能避免使用三个参数(三元)。多于三个(polyadic)需要非常特殊的证明——然后无论如何都不应该使用。

通过查看您提出的不相关示例,我可以直接说这不是好的 OOP 设计,不仅在公开的公共接口方面,而且在关系方面(应该通过适当的推理创建层次结构)。也许如果您提出一个真实世界的案例,我可以进一步建议进行适当的重构,但是使用没有用例的无意义的虚构代码和虚构的无意义参数,我看不出重点。

在任何情况下,我能给你的最好建议是尝试提出具有适当逻辑关系和精简的不言自明的公共接口的良好封装对象。否则,让你的代码“有吸引力”和“令人愉快”以供其他人使用,你会没事的:)


推荐阅读