当我定义函数时,我应该以什么顺序放置参数?

时间:2011-01-19 14:15:33

标签: language-agnostic coding-style conventions

我经常发现很难决定并且不一致。我可以遵循一些规则吗?

例如:

def remove_except(haystack, needle, exclude_value):
    for key in hackstack:
        if key in needle and haystack[key] != exclude_value:
            hackstack.pop(key)

可能很容易:

def remove_except(needle, exclude_value, haystack):
    for key in hackstack:
        if key in needle and haystack[key] != exclude_value:
            hackstack.pop(key)

不是一个完美的例子,因为我倾向于将被修改的变量作为第一个参数,例如干草堆,这甚至可能是一个惯例,但除此之外,我不确定该怎么做。

我对比Python更多的语言感兴趣。

7 个答案:

答案 0 :(得分:3)

唯一的规则是保持一致。这不仅意味着在您定义的API之间和之内保持一致,而且还与环境中常用的任何API保持一致。请注意,这可能意味着您在一个环境中执行的操作与在另一个环境中执尽量适应。

现在,使用Python和JavaScript,您可以使用面向对象至少使干草堆无法解决问题,因为干草堆将(或者至少可以成为您的对象)重新操作,因此你将如何做到这一点将由语言决定(例如,delete haystack[needle]; [用于从对象中删除属性的JavaScript]或del haystack[needle] [用于删除字典条目的Python])。 C不是面向对象的(C ++,D,Objective-C和其他几个派生词),所以你需要在那里寻找约定。

主观上说,根据我的经验,haystack通常是第一位的,但这可能只是我的经历。同样,我的主观意见是exclude_value将是最后一件事(因此,haystackneedleexclude_value)因为会有其他操作需要{ {1}},haystackneedle - 但这只是一种意见。

答案 1 :(得分:1)

我相信大会是从左到右,最重要的,至关重要的。所以对于你的例子我会做(针,haystack,exclude_value)。在这种情况下,针是最重要的,因为它是呼叫的定义信息。同一个干草堆可以用于另一个不同针的呼叫。 Exclude_value似乎可以是可选的。

答案 2 :(得分:1)

这完全取决于你。如果您正在编写一个与包含项目中的任何其他功能不同的单个函数,那么必需/重要参数首先是可选/不重要的跟踪。您正在使用的语言可能影响选择; Python允许提供可选的命名参数或关键字参数,但它们必须遵循位置参数。

如果您正在为API编写一组类似的函数,那么一致性变得更加重要。使用haystack示例,您可能有

def insert(haystack, needle)
def remove(haystack, needle)
def remove_except(haystack, needle, exclude_value)
def copy(haystack, haystack2)

干草堆首先出现,因为它是所有列出的方法的关键参数,并且具有

def remove(needle, haystack)
def remove_except(haystack, needle, exclude_value)

看起来很奇怪(但当然还是可以的)。

如果您使用面向对象的语言并且发现自己编写了大量共享参数的函数,那么您可能会考虑将该对象和操作该对象的函数方法设置为但是这可能超出了该范围。问题

对于您选择的语言,找一些常用的代码并进行研究。如果您使用的是Python,请查看标准库。对于Javascript,jQuery可能会很好。

答案 3 :(得分:1)

正如“将干草堆放在首位”的合唱的一些支持信息,在这种情况下主要用于JavaScript :当你在考虑哪个参数是“最重要的”,或者哪个它是“干草堆”,它(可以)帮助考虑调用之间哪个参数可能不同,哪些参数可能会发生变化。在你的例子中,“needle”从调用到调用可能非常不稳定,而“haystack”可能总是或几乎总是相同的。

如果是这种情况 - 对于一个特定对象使用类似的实用程序是很常见的 - 新的JavaScript环境中可用的“bind()”方法(在Function原型上),或者像Prototype这样的库添加或功能,非常有用:

function whatever(haystack, needle) {
  // ...
};

var myHaystack = new Haystack( /* ... */ );

var myHaystackWhatever = whatever.bind(null, myHaystack);

现在函数“myHaystackWhatever”可以像这样使用:

var result = myHaystackWhatever(someNeedle);

这可能看起来微不足道,但是在像JavaScript这样的函数式语言中,能够轻松可靠地创建新函数作为现有函数的变体是非常方便的,可以节省大量的输入和paren / brace匹配混乱。

这里的重点是像“绑定”这样的工具,特别是在JavaScript中,它将调用值与形式参数的纯粹基于订单的绑定绑定在一起,从左到右绑定固定值。因此,如果你最左边的参数是最可能是一个不同的东西,那么“bind()”并不是太有趣。 (功能JavaScript库有一种绑定其他参数的方式,而不仅仅是从左到右,但它非常奇特和奇怪,在我看来,作为一个编码示例,它最有趣。)

答案 4 :(得分:0)

我相信这完全取决于你。

答案 5 :(得分:0)

在您的示例中,我将从正在操作的对象开始或执行操作。然后是最必要的参数。所以干草堆,针,排除价值。如果有可能有另一个版本的函数丢弃了一些参数(例如没有排除值),这些通常会在最后。我现在在C中思考,但你的例子是python,所以有可能处理可选或默认参数......

答案 6 :(得分:0)

除了“非正式”一致性规则或“最重要到最不重要”之外,还有一些语言规则需要在Python中观察:

函数定义可以包含(按此顺序):

  • 位置参数(即没有默认值的必需参数),
  • 关键字参数(即可选参数,其中在函数定义期间指定了默认值),
  • 变量参数(即未指定数量的未命名参数)和/或
  • 变量关键字参数(即,未指定数量的自由“可命名”关键字参数)

所以你可以写

def myfunc(x, y, z=0, truncate=True, *args, **kwargs):
    do_something()

然后可以被称为

myfunc(1,2)
myfunc(1,2,3,False)
myfunc(1,2,3,True, "some more args", mykeyword="keyword arg")

但你无法定义这样的函数:

def wontwork(x=0, y, z):
def wontworkeither(*args, debug=True)

Python Tutorial

详细介绍了这一点