我如何编写自己的函数来接受和使用函数作为参数?

How can I write my own function that accepts and uses a function as a parameter?

我在标准库和主要的第三方库中看到了几个接受函数作为输入的函数(和方法)的例子

例如,考虑 Pandas DataFrameapply method。该方法的文档建议您可以将 sum()numpy.sqrt() 之类的另一个函数传递给函数,例如 apply(sum)apply(numpy.sqrt).

同样,标准库 sorted 函数明确记录了

key specifies a function of one argument that is used to extract a comparison key from each element in iterable (for example, key=str.lower).

如何编写自己的函数以这种方式工作,接受一个函数作为输入之一?

执行此操作的方式与编写函数以接受 任何其他内容 的方式相同。 Python 的 def 语句不需要任何类型说明:

def example(parameter):
    pass

你可以传递任何对象;函数是对象;因此,您可以传递函数:

def argument():
    print("This message won't be printed this time, but keep reading")

example(argument)

为了能够将函数作为参数传递,您什么都不做

同样适用于方法和普通函数:

class Example:
    def method(self, parameter):
        pass

Example().method(argument)

“但是我如何在函数内部使用它呢?”

除非你正在做一些真的不寻常的事情(在研究层面远远超出这个问题),唯一真正有趣的是使用函数做的事情 - 除了像传递它一样这-就是调用它。

通过获取函数调用函数,然后在其后写入 function-call 语法(括号之间的参数列表)。函数是对象;您通过评估表达式获得对象;因此,您可以通过计算表达式来获得函数(只要它确实计算为函数)。

通常,该表达式是...函数的名称,在全局命名空间中查找(如上例所示)。但就像任何其他对象的情况一样,您可以通过其他方式进行。

特别是,您可以为该值指定其他名称 - 例如,将其作为参数传递。这就是调用函数时发生的情况:函数使用其参数名称 作为 的名称,无论作为参数传递什么。

包括如果那是另一个功能。

然后,在被调用函数中,您通过命名传递函数来调用它 - 使用参数名称 - 然后使用正常的函数调用语法。

def example(parameter):
    parameter()

现在打印了(误导性的)消息。

可以使用更复杂的表达式。一种常见的模式是在字典中查找它们(尽管 3.10 的 match... case 构造使这个 稍微 不太有用)。另一种方法是动态编译代码(为此有很多方法;所有这些方法至少都有点危险,所以我不会在这里命名或展示它们。合法使用它的人也有能力做必要的研究。)

发生什么事是因为您在函数 apply 中只在内存中为函数 sum 提供 link。在你的 apply 函数中,这个 link 将被调用。

def apply(some_func):
    result = some_func(28, 79)
    return result

此函数 returns 求和 28 和 79 (107)。

接受其他函数作为参数或返回函数的函数被调用higher-order function

所以 Panda 的 apply() 是一个 higher-order 函数。它接受另一个功能,例如sum 并在内部调用或调用它作为 sum(args).

要定义接受函数作为参数的 higher-order 函数,请使用与普通函数一样的签名。

在下面的示例中,这将是 def md_heading(phrase):

如何调用功能参数(不带参数)

查看如何调用预期为函数的参数:

def md_heading(phrase):
    return "# " + phrase()

注:

  • 此处的参数命名方式类似于变量名 - 而不是像 Panda apply(func).
  • 中那样使用需要函数的明确表示法
  • 此参数 phrase 仍应为 function-reference,因为它将使用括号(不带参数)调用。
  • md_heading() 是包装函数,phrase 函数参数。

传递文字

现在尝试将 字符串文字 像`'Hello World' 作为参数传递时会发生什么。

result = md_heading('Hello World')  # this would pass it in, then try to call it .. and ?
print(result)

调用作为参数传递的字符串将引发错误。 确切地说 return "# " + phrase() 为:

TypeError: 'str' object is not callable

传递函数(引用)作为参数

现在你应该传递一个函数作为参数,但只是作为参考(不带括号):

def greeting():
   return 'Hi'

result = md_heading(greeting)
print(result)

打印:Hi

传递 lambda 作为参数

或者您可以传递一个 lambda 作为参数:

result = md_heading(lambda: "Hello!")
print(result)

打印:'Hello!

注意:lambda 不能有位置参数。这接近于传递一个常量,就像开头的字符串一样。

传递 lambda 时没有(必需)参数

当我们在此处使用 lambda name: "Hello " + name 等位置参数定义 lambda 时,它将引发:TypeError: <lambda>() missing 1 required positional argument: 'name' 因为在我们的 higher-order 函数中它是在没有参数的情况下调用的,就像 phrase().