Language agnostic 定义函数时,应按什么顺序放置参数?

Language agnostic 定义函数时,应按什么顺序放置参数?,language-agnostic,coding-style,conventions,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_valu

我经常发现很难做出决定,而且前后矛盾。有什么规则我可以遵守吗

例如:

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)
这不是一个完美的例子,因为我倾向于将被修改的变量作为第一个参数,例如haystack,这甚至可能是一个惯例,但除此之外,我不确定该怎么做


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

我相信这完全取决于您。

唯一的规则是保持一致性。这不仅意味着在您定义的API之间和内部保持一致,还意味着与环境中常用的任何API保持一致。请注意,这可能意味着您在一种环境中做的事情与在另一种环境中做的事情不同。试着适应

现在,有了Python和JavaScript,您可以使用面向对象的方法来消除至少草堆的问题,因为草堆将是(或至少可以是)您正在操作的对象,因此如何操作将由语言决定(例如,
delete haystack[needle];
[JavaScript用于从对象中删除属性]或者
delhaystack[needle]
[Python用于删除字典条目])。C不是面向对象的(C++、D、Objective-C和其他一些派生语言都是面向对象的),因此您需要在那里寻找约定


主观地说,根据我的经验,
haystack
通常排在第一位,但这可能只是我的经验。类似地,我的主观意见是,
排除值
将是最后一件事(因此,
干草堆
排除值
),因为还有其他操作需要
干草堆
其他的东西
——但这只是一种观点。

我认为这个惯例从左到右,从最重要到最不重要。所以对于你的例子,我会做(针,草堆,排除_值)。针在这种情况下是最重要的,因为它是呼叫的定义信息。同样的草垛可以用不同的针在另一次通话中使用。Exclude_值似乎是可选的。

在您的示例中,我将从正在操作或执行操作的对象开始。然后首先是最必要的参数。所以草垛,针,排除值。如果有可能删除另一个版本的函数的某些参数(例如,没有排除的值),通常会在最后删除这些参数。我现在正在考虑使用C语言,但您的示例是python,因此有可能处理可选或默认参数…

除了一致性的“非正式”规则或“从最重要到最不重要”之外,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)
var result = myHaystackWhatever(someNeedle);

这将在中详细介绍。

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

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

def insert(haystack, needle)
def remove(haystack, needle)
def remove_except(haystack, needle, exclude_value)
def copy(haystack, haystack2)
其中haystack是第一个,因为它是所有列出的方法的关键参数

def remove(needle, haystack)
def remove_except(haystack, needle, exclude_value)
看起来很奇怪(但当然仍然有效)

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


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

就像“把干草堆放在第一位”的一些支持信息一样,在这种情况下,主要是针对Javascript的:当您考虑哪个参数是“最重要的”,或者哪个是“干草堆”时,它(可以)帮助思考调用之间哪个参数可能不同,哪个参数可能更改。在您的示例中,“针”可能在每次调用中都非常不稳定,而“干草堆”可能总是,或者几乎总是相同的东西

如果是这样的话——通常只对一个特定对象使用这样的实用程序——在新的JavaScript环境(在函数原型上)中可用的“bind()”方法,或者由库(如原型或函数)添加的“bind()”方法,可能非常有用:

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

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

var myHaystackWhatever = whatever.bind(null, myHaystack);
现在,函数“myHaystackWhatever”可以这样使用:

def wontwork(x=0, y, z):
def wontworkeither(*args, debug=True)
var result = myHaystackWhatever(someNeedle);
这可能看起来很简单,但在JavaScript这样的函数式语言中,作为现有函数的变体轻松可靠地创建新函数的能力非常方便,从而避免了大量的键入和括号匹配混乱

这里的要点是,像“bind”这样的工具,特别是在JavaScript中,调用值与形式参数的绑定完全基于顺序,可以从左到右绑定固定值。因此,如果最左边的参数最有可能是无数不同的参数,那么“bind()”就不太可能了