这在很大程度上取决于上下文。
基本上,如果函数是 的参数bar
,那么调用者有责任知道如何实现该函数。bar
不必在意。但因此,bar
的文档必须描述它需要什么样的功能。
通常这是非常合适的。最明显的例子是map
内置函数。map
实现将函数应用于列表中的每个项目并返回结果列表的逻辑。map
它本身既不知道也不关心这些项目是什么,或者函数对它们做了什么。map
的文档必须描述它需要一个参数的函数,并且每个调用者map
都必须知道如何实现或找到合适的函数。但是这种安排很棒;它允许您传递自定义对象的列表,以及专门对这些对象进行操作的函数,并且map
可以离开并执行其通用操作。
但这种安排往往是不合适的。函数为高级操作命名并隐藏内部实现细节,因此您可以将操作视为一个单元。允许其部分操作作为函数参数从外部传入,这表明它以使用该函数接口的方式工作。
一个更具体(虽然有些人为)的例子可能会有所帮助。假设我已经实现了表示Person
and的数据类型Job
,并且我正在编写一个函数name_and_title
,用于将某人的全名和职位格式化为字符串,以便客户端代码插入电子邮件签名或信头或其他任何内容。这显然需要一个Person
and Job
。它可能需要一个函数参数来让调用者决定如何格式化人名:类似于lambda firstname, lastname: lastname + ', ' + firstname
. 但这样做是为了暴露我用单独的名字和姓氏来代表人们的名字。如果我想更改为支持中间名,那么要么name_and_title
将无法包含中间名,或者我必须更改它接受的函数的类型。当我意识到有些人有 4 个或更多名称并决定更改为存储名称列表时,我肯定必须更改函数name_and_title
接受的类型。
所以对于你的bar
例子,我们不能说哪个更好,因为它是一个没有意义的抽象例子。这取决于调用是否是应该做partialfun
的任何事情的实现细节,或者调用是否是调用者知道的事情(并且可能想要做其他事情)。如果它是 "part of" ,那么它不应该是一个参数。如果它是调用者的“一部分”,那么它应该是一个参数。bar
partialfun
bar
值得注意的是,它bar
可能有大量的函数参数。您调用sum
、map
和operator.mul
,它们都可以被参数化以使其bar
更灵活:
def bar(fn, xs,ys, g, h, i):
return fn(g(h(i,xs,ys))
也可以抽象g
出调用输出的方式:h
def bar(fn, xs, ys, g, h, i, j):
return fn(j(g, h(i, xs, ys)))
而且我们可以一直继续下去,直到bar
什么都不做,一切都由传入的函数控制,调用者还不如直接做他们想做的事情,而不是写100个函数来做并将它们传递bar
给执行功能。
因此,实际上并没有一个始终适用的明确答案。这取决于您正在编写的特定代码。