我一直在查看我正在使用的开源包的源代码。几乎每个函数都使用 *args 而不是命名参数。我发现很难遵循和使用代码,因为每次我想调用一个函数时,我都必须返回,挑选源代码,并确定参数应该是什么,以及它们应该是什么顺序。我的问题是:是否有令人信服的理由在每个函数中使用 *args,或者这是对这个概念的滥用?谢谢,-b
5 回答
这可能是个人原因,但我只使用 *args 和 **kwargs 当我有很多可选字段时,其中一些字段仅在特定上下文中使用。
我使用 args 的唯一其他场合是为云 API 构建 XML RPC 客户端时。由于我只是将参数传递给底层并且由于函数是动态生成的,因此我别无选择,只能使用 *args,因为我无法提前知道所有参数。
在大多数情况下,您甚至都不需要它。我认为这主要是懒惰而不是其他任何事情。
一些来自 Java 和 C# 的人可能会使用它作为“params”的替代品,但是在 python 中传递可选参数的方法有很多。
而且我同意即使你使用 *args,你也应该有一个非常好的文档。
在每个函数中使用*args
是一个坏主意,因为它可以掩盖代码中的错误(调用具有错误数量参数的函数)。我想经验法则应该是只*args
在需要 *args
时使用。
在Python 之禅中,我们被告知要显式而不是隐式。应尽可能使用显式参数。
当没有令人信服的理由使用*args
时,这是对概念的滥用。通常有很好的参数名称,有助于理解。即使没有,也(x, y, z)
告诉你更多(*args)
。
除了使代码更具可读性之外,它还有助于捕获错误(例如,如果你调用一个(x, y, z)
函数,(2, 3)
你会在调用时得到一个错误,而不是在函数内部),它通常更简洁,甚至可以更高效。
但有时有令人信服的理由广泛使用*args
.
例如,如果您正在包装一个较低级别(C 或其他)模块并希望进行完美转发,那么使用*args
. 如果您自动生成包装器代码而不是手动编写它,则更是如此。当然,这仍然是一个折衷——这对包装模块的开发者来说更容易,但对用户来说更难——但有时这种折衷是值得的。
在不知道您所指的特定包的情况下,不可能猜测它是一个引人注目的用例还是滥用。
如果你包装一个未知函数(装饰器返回的函数经常这样做),那么你经常需要使用(*args, **kwargs)
.
一些类层次结构(*args, **kwargs)
在可能需要层次结构中不同类的不同签名的方法中使用(__init__
是罪魁祸首)。如果您可以避免这种情况,这真的很有帮助,但是可能有必要以理智的方式处理多重继承层次结构(或者至少尽可能理智地处理多重继承)。
**kwargs
当我有大量可选参数时,我有时最终会使用,但这需要大量文档。
在一个消耗*args
自身的函数中(而不是将它们传递给具有未知签名的其他函数,如在装饰器或类继承案例中),那么我倾向于认为*args
几乎不应该使用它,除了表示“零个或多个一样的东西”。在这种情况下,您应该将其命名为*websites
or *spaceships
or *watermelons
, not *args
。一堆不相关的参数不应该被压缩到*args
. 更糟糕的是,函数使用*args
“an x, ay, and az, or else an x and a z”,其中第二个参数根据传递的参数数量做不同的事情。到那时,它们显然都应该有名称和默认值(即使这只是标准None
default 然后在函数中查看哪些是非None
模式的)并通过关键字而不是位置传递。