Python中传递函数参数的惯用方法是什么?

9

我正在处理一个几乎所有地方都使用关键字传递参数的项目。有些函数只有位置参数,有些函数有关键字(默认值)参数,还有一些函数混合了两种参数。例如下面这个函数:

def complete_task(activity_task, message=None, data=None):
    pass

在当前代码中,此函数将像这样被调用:

complete_task(activity_task=activity_task, message="My massage", data=task_data)

对我而言,在函数执行的上下文或变量名称中已经明显的参数命名是没有意义的。我会这样称呼它:

complete_task(activity_task, "My message", task_data)

在某些情况下,如果从上下文或变量名称中无法清楚地确定调用参数,我可能会这样做:

complete_task(activity_task, message="success", task_data=json_dump)

这让我想知道,当没有必要重新排列方法参数或使用一些关键字参数的默认值时,有没有一种约定俗成或"pythonic"的方法来调用带有位置参数/关键字参数的函数。


3
你混淆了函数和方法的概念。你发帖中提到的所有内容都是函数,而不是方法。 - Tom Karzes
2
@TomKarzes:嗯,Python几乎不区分这些东西。方法只是一个附加到类上(并通过类访问)的函数而已。 - Kevin
@TomKarzes 抱歉,我自己纠正了。我指的是“方法”,因为项目中大多数情况下都是实际方法,但对于上面的简单示例,我将其编写为函数。不过,我认为问题中的其他所有内容仍然适用。 - ddinchev
1
@Kevin 对,这基本上就是方法的定义。Python在区分方法和其他语言方面并没有更多或更少的差别。方法只不过是带有一些额外上下文的函数。它们可以绑定或未绑定。但它们与裸函数有所区别。这就是为什么有两个不同的术语。如果你想淘汰“方法”这个术语,并把所有东西都称为函数,那就随你便吧。但是,虽然把方法称为函数并不是不正确的,但把函数称为方法是错误的。方法是函数的特殊情况,但反过来则不成立。 - Tom Karzes
@TomKarzes 没有人试图与您就 methodfunction 的含义进行争论。在具体的例子中,由于我省略了第一个 "self" 参数,因此不应将 function 称为 method。除此之外,一切都没有变化。我认为,在命名问题上进行争吵是没有意义的,尤其是当它甚至没有影响到问题本身时,这可能就是 Kevin 的意思。 - ddinchev
2个回答

4
我遵循的通常规则是:
  1. 布尔值,特别是布尔字面量,应始终通过关键字传递,除非它们的含义真的非常明显。这很重要,以至于在编写自己的函数时,我经常会将布尔参数设置为仅限关键字。如果您有一个布尔参数,您的函数可能需要拆分成两个较小的函数,特别是如果它采用if boolean_parameter: do_something(); else: do_something_entirely_different()的总体结构。
  2. 如果一个函数有很多可选参数(包括必需参数在内超过~3个),那么选项通常应该通过关键字传递。但是,如果您有很多参数,您的函数可能需要重构为多个较小的函数。
  3. 如果一个函数接受多个相同类型的参数,则它们可能需要作为关键字参数传递,除非从上下文中完全明显顺序(例如srcdest之前)。
  4. 大多数情况下,关键字参数都不是错误的。如果您有一个位置参数混乱的情况,您应该毫不犹豫地使用关键字参数。除了简单的单参数函数可能有例外,关键字参数不会使您的代码更难阅读。

1
Python有两种类型的参数1位置参数和关键字参数(也称为默认参数)。由于位置参数可以通过关键字调用,而关键字参数也可以通过位置调用,因此情况有些复杂...
def foo(a, b=1):
   print(a, b)

foo(1, 2)
foo(a=1, b=2)

说到这里,我认为参数类型的名称应该表明你应该(通常)如何使用它们。大多数情况下,我看到按位置调用位置参数,按关键字调用关键字参数。因此,如果你正在寻找一个通用的经验法则,我建议你使函数调用模仿签名。对于我们上面的foo函数,我会这样调用:

foo(1, b=2)

我认为遵循这个建议的一个原因是,大多数情况下人们希望通过关键字来传递关键字参数。因此,有时候会有人稍后添加一个关键字,这并不罕见:

def foo(a, aa='1', b=2):
    print(a, aa, b)

如果您仅使用位置参数调用函数,则现在传递的值与之前不同。但是,关键字参数不关心您传递它们的顺序,因此您仍然可以全部设置。
到目前为止,一切都很好。但是,在创建函数时应该使用什么规则呢?您如何知道将参数设置为默认参数还是位置参数?这是一个合理的问题 - 很难找到一个好的经验法则。我使用的经验法则如下:
1. 与项目的其余部分保持一致 - 如果您做的事情与周围代码不同,则很难做到正确。 2. 如果可能提供合理的默认值,请将参数设置为默认参数。如果用户没有提供特定参数会导致函数失败(因为没有好的默认值),则应该是位置参数。
Python3.x也有关键字only参数。这些参数不给你选择,所以我不知道它们在这里是否会增加太多讨论的内容 :-) -- 虽然我不知道我是否在野外看到过它们的使用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接