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