【问题标题】:Proper use vs. over use of *args in Python在 Python 中正确使用与过度使用 *args
【发布时间】:2012-09-19 23:41:00
【问题描述】:

我一直在查看我正在使用的开源包的源代码。几乎每个函数都使用 *args 而不是命名参数。我发现很难遵循和使用代码,因为每次我想调用一个函数时,我都必须返回,挑选源代码,并确定参数应该是什么,以及它们应该是什么顺序。我的问题是:是否有令人信服的理由在每个函数中使用 *args,或者这是对这个概念的滥用? 谢谢, -b

【问题讨论】:

  • 如果有 *args,则需要有一个(准确的!)文档字符串。
  • 它是什么包?不玩指责游戏,但他们可能有正当理由。

标签: python arguments maintainability


【解决方案1】:

这可能是个人原因,但是当我有很多可选字段且某些字段仅在特定上下文中使用时,我只使用 *args 和 **kwargs。

我使用 args 的唯一其他场合是在为云 API 构建 XML RPC 客户端时。由于我只是将参数传递给底层并且由于函数是动态生成的,因此我别无选择,只能使用 *args,因为我无法提前知道所有参数。

在大多数情况下,您甚至都不需要它。我认为这主要是懒惰。

一些来自 Java 和 C# 的人可能会使用它作为“参数”的替代品,但是在 python 中传递可选参数的方法有很多。

而且我同意即使你使用 *args,你也应该有一个非常好的文档。

【讨论】:

  • 在两年的 C# 编码中,我使用了两次params。在 Python 的一个月里,我看到(*args, **kwargs) 的次数太多了,我的眼睛都在流血。我建议谨慎使用它;这是一个应该用来解决非常具体的问题的工具。正如我们所知,当您为人们提供如此易于使用的工具时,他们会无休止地过度使用和滥用它。
【解决方案2】:

在每个函数中使用*args 是个坏主意,因为它会掩盖代码中的错误(调用带有错误数量参数的函数)。我想经验法则应该是只在需要 *args时使用*args

【讨论】:

    【解决方案3】:

    Zen of Python 中,我们被告知更喜欢显式而不是隐式。应尽可能使用显式参数。

    【讨论】:

    • @nneonneo 在没有进一步评论的情况下引用禅宗是非常没用的。 Python 之禅中的指导方针很棒,但不仅仅是因为它们属于 Python 之禅,它们是很好的理由的好主意。在不理解这些准则的原因(以便您在偏离它们时能够识别)的情况下记住 Python 之禅并不能帮助您很好地应用它们。
    • @Ben,我不认为这是我推测为什么该特定项目出现在 Zen 中的地方。在这种情况下,我认为这很明显——显式更容易理解和遵循。我还发现,使用指导您的平台设计人员的相同原则只会让整体情况变得更好,而不仅仅是在 Python 中。
    【解决方案4】:

    如果没有令人信服的理由来使用 *args,那就是对这个概念的滥用。通常有很好的参数名称,有助于理解。即使没有,(x, y, z)(*args) 告诉你更多。

    除了使代码更具可读性之外,它还有助于捕获错误(例如,如果您使用 (2, 3) 调用 (x, y, z) 函数,您将在调用时收到错误,而不是在函数内部),它是通常更简洁,甚至可以更高效。

    但有时有令人信服的理由广泛使用*args

    例如,如果您正在包装较低级别(C 或其他)模块并希望进行完美转发,使用*args 会更容易。如果您自动生成包装器代码而不是手动编写它,则更是如此。当然,这仍然是一个折衷——它对包装模块的开发者来说更​​容易,但对用户来说更难——但有时这种折衷是值得的。

    在不知道您所指的特定软件包的情况下,无法猜测它是令人信服的用例还是滥用。

    【讨论】:

      【解决方案5】:

      如果你包装一个未知函数(装饰器返回的函数经常这样做),那么你经常需要使用(*args, **kwargs)

      某些类层次结构在可能需要层次结构中不同类的不同签名的方法中使用(*args, **kwargs)__init__ 是罪魁祸首)。如果您可以避免这种情况,这真的很有帮助,但可能有必要以理智的方式处理多重继承层次结构(或者至少尽可能理智地处理多重继承)。

      当我有大量可选参数时,我有时最终会使用**kwargs,但这需要大量文档。

      在使用 *args 本身的函数中(而不是将它们传递给具有未知签名的其他函数,如在装饰器或类继承案例中),那么我倾向于认为 *args 几乎永远不会用于表示“零个或多个相同种类的东西”。在这种情况下,您应该将其命名为 *websites*spaceships*watermelons,而不是 *args。一堆不相关的参数不应该被压缩成*args。更糟糕的是函数使用 *args 来获取“一个 x、一个 y 和一个 z,或者一个 x 和一个 z”,其中第二个参数根据传递的参数数量来做不同的事情。在这一点上,它们显然都应该有名称和默认值(即使它只是标准的None 默认值,然后在函数中查看哪些是非None 模式)并通过关键字而不是位置传递。

      【讨论】:

        猜你喜欢
        • 2022-11-02
        • 1970-01-01
        • 1970-01-01
        • 2023-04-01
        • 2013-05-23
        • 1970-01-01
        • 1970-01-01
        • 2015-10-05
        • 1970-01-01
        相关资源
        最近更新 更多