Python 中的回调函数

转自: https://www.askpython.com/python/built-in-methods/callback-functions-in-python
稍作翻译和引申,比较简单的概念

Python 中的回调函数

Callback functions in Python – A Complete Overview

A callback is a general concept in Python as well as other languages like Javascript, C, etc. We know that Python is an object-oriented language and functions are first-class objects in Python. This means, in Python, we can assign the value returned by a function to a variable and return a function from another function.

回调是 Python 以及 Javascript、 C 等其他语言中的一个普遍概念。我们知道 Python 是一种面向对象的语言,函数是 Python 中的一等对象。这意味着,在 Python 中,我们可以将函数返回的值赋给一个变量,并从另一个函数返回一个函数。

In this tutorial, we will learn about the concept of callback in Python programming language and we will also see a few examples related to it. So let’s get started.

在本教程中,我们将学习 Python 回调的概念,并且我们还将看到一些相关的例子。我们开始吧。

Python 中的回调函数

Callback functions in Python

When one function is called from another function it is known as a callback. A callback function is a function that is passed to another function as an argument. It can be done in two ways:

当从另一个函数调用一个函数时,它被称为回调函数。回调函数是作为参数传递给另一个函数的函数。这可以通过两种方式实现:

  1. Passing one function as an argument to another function将一个函数作为参数传递给另一个函数
  2. Calling a function inside another function在另一个函数中调用函数

The above two points can help you decide if a given function is a callback function or not. It is not necessary that both the above conditions be true for a function to be a callback function. Even if one of the above two conditions is satisfied, the function is termed a callback function.

以上两点可以帮助您确定给定的函数是否是回调函数。一个函数要成为回调函数,不一定要满足上述两个条件。即使满足上述两个条件之一,该函数也称为回调函数。

Callbacks can be implemented using both built-in functions as well as user-defined functions. We will be seeing examples for both implementations in this tutorial.

可以使用内置函数和用户定义函数来实现回调。在本教程中,我们将看到这两种实现的示例。

使用内置函数进行回调

Callback using built-in functions

We are all familiar with the sorted function in Python. Let’s just have a quick recap of it first.

我们都熟悉 Python 中的排序函数。

语法:Syntax:

sorted(iterable, key)
Parameter参数Meaning含义
iterable (mandatory必选)Data structure that is to be sorted (List, dictionary, etc.)待排序的数据结构(列表、字典等)
key (keyword, optional可选)Criteria for sorting. It can be assigned any function that you want to use.排序的条件。它可以分配给你想要使用的任何函数。

When the sorted function is called, the iterable will be first passed to the key function and it will implement on the iterable. Then the new/changed iterable will be sorted.

当调用排序函数时,迭代器将首先传递给键函数,并在迭代器上实现。然后对新的/更改后的迭代器进行排序。

Here, we are calling the key function inside the sorted function. So, the second condition is satisfied here. Hence, the key function here is a callback function.

这里,我们调用排序函数中的 key 函数。这里满足第二个条件。因此,这里的关键函数是一个回调函数。

Let’s see an example. Suppose we have to sort a list of strings.

让我们来看个示例,假设我们要对一系列的字符串进行排序

#list列表
a = ["lmn", "AbCd", "khJH", "ert", "SuNnY"]

#sorted based on the ASCII values默认的字符串排序是基于ASCII值
print(sorted(a))

#first convert all letters to lowercase & then sort based on ASCII values先对所有的字符转换成小谢再进行排序(依然是基于ASCII)
print(sorted(a, key=str.lower))

Output:

['AbCd', 'SuNnY', 'ert', 'khJH', 'lmn']
['AbCd', 'ert', 'khJH', 'lmn', 'SuNnY']

If you recall, the ASCII value for ‘A’ is 65, ‘B’ is 66, ‘e’ is 101 and so on. Please refer to this link for the ASCII values table.
So, in the first case, the list is sorted based on the ASCII values only.

如果您还记得,‘ A’的 ASCII 值是65,‘ B’是66,‘ e’是101,以此类推。有关 ASCII 值表,请参考此链接。

因此,在第一种情况下,列表仅根据 ASCII 值进行排序

If we observe the list, we can see that the strings inside the list are a mixture of uppercase as well lowercase alphabets. Let’s say, we now want to sort the list based on only the lowercase form of each letter. For this purpose, we have introduced a new parameter in the function key=str.lower.

如果我们观察列表,我们可以看到列表中的字符串是大写字母和小写字母的混合。比方说,我们现在希望仅根据每个字母的小写形式对列表进行排序。为此,我们在函数 key = str.lower 中引入了一个新参数。

Here, the str.lower is first implemented on the iterable list. That is, the strings in the list are converted into lowercase. So now, the list actually is 'lmn', 'abcd', 'khjh', 'ert', 'sunny' and this list is then passed to the sorted function

在这里,str.lower 首先在可迭代列表上实现。也就是说,列表中的字符串被转换为小写。现在,列表实际上是‘ lmn’,‘ abcd’,‘ khjh’,‘ ert’,‘ sun’,然后这个列表被传递给排序函数。

Notice that the all lowercase list is different from the original list, but here ‘lmn’ represents ‘lmn’, ‘abcd’ represents ‘AbCd’, ‘khjh’ represents ‘khJH’, ‘ert’ represents ‘ert’ and ‘sunny’ represents ‘SuNnY’ in the original list. The sorted version of the new list is 'abcd', 'ert', 'khjh', 'lmn, 'sunny', hence the output is the one shown above.

So, this is how callback works in built-in functions in Python.

注意,all 小写列表与原始列表不同,但是这里‘ lmn’代表‘ lmn’,‘ AbCd’代表‘ AbCd’,‘ khJH’代表‘ khJH’,‘ ert’代表‘ ert’,而‘ sun’代表原始列表中的‘ SuNnY’。新列表的排序版本是“ abcd”、“ ert”、“ khjh”、“ lmn”、“ sun”,因此输出如上所示。

因此,这就是 Python 内置函数中回调的工作方式。

用户自定义函数中的回调

Callback in user-defined functions

Let us now learn about callbacks in user-defined functions. Let the function that ‘calls’ a function has the name caller and the one being called have the name called. Here, the caller function can be said to be a master and the called function as a slave, as the master function can always call the slave function but not vice-versa.

现在让我们了解用户定义函数中的回调。让“调用”函数的函数具有名称调用者,而被调用的函数具有被调用的名称。这里,调用函数可以说是主函数,被调用函数可以说是从函数,因为主函数总是可以调用从函数,而不是相反。

Suppose we are given a tuple consisting of two integers and we need to calculate the multiplication of these two integers.

假设给我们一个由两个整数组成的元组,我们需要计算这两个整数的乘法。

def called(n):
    return n[0]*n[1]

def caller(func, n):
    return func(n)

#tuple
num = (8, 5)

ans = caller(called, num)

print("Multiplication =", ans)

Output:

Multiplication = 40

In the above code, we have defined two functions: caller and called. The called function is passed as an argument to the caller function. Hence, the first condition is satisfied here, so this is also a case of callback and called is the callback function here.

在上面的代码中,我们定义了两个函数: 调用方和调用方。被调用的函数作为参数传递给调用方函数。因此,这里满足了第一个条件,所以这也是回调的情况,在这里调用的是回调函数。

When the program is executed, first, the tuple is created then the caller function is called. Now, the control goes to the definition of the caller function. It takes two arguments: a function (func) and an iterable (n), which is a tuple in this case. In caller function, it is desired that the function passed as argument is applied on the iterable and the result (func(n)) be returned.

So now, the control is at the called function definition. It takes a tuple as an argument and returns the multiplication of its members. This value is then returned to the caller function and then the caller function returns the answer i.e. 8×5 = 40.

当程序执行时,首先创建元组,然后调用调用方函数。现在,控件转到调用方函数的定义。它有两个参数: 一个函数(func)和一个 iterable (n) ,在本例中是一个元组。在调用方函数中,需要将作为参数传递的函数应用于迭代器,并返回结果(func (n))。

现在,控件位于被调用的函数定义处。它接受元组作为参数,并返回其成员的乘法运算。然后这个值返回给调用方函数,然后调用方函数返回答案,即8 × 5 = 40。

小结

Hence, we have learned about callbacks in Python and also how they are implemented using both built-in as well as user-defined functions.

因此,我们了解了 Python 中的回调,以及如何使用内置函数和用户定义函数实现回调。

参考

https://www.zhihu.com/question/19801131/answer/13005983

作者:常溪玲

你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件

https://www.zhihu.com/question/19801131/answer/27459821

作者:no.body

什么是回调函数?

我们绕点远路来回答这个问题。

编程分为两类:系统编程(system programming)和应用编程(application programming)。所谓系统编程,简单来说,就是编写;而应用编程就是利用写好的各种库来编写具某种功用的程序,也就是应用。系统程序员会给自己写的库留下一些接口,即API(application programming interface,应用编程接口),以供应用程序员使用。所以在抽象层的图示里,库位于应用的底下。

当程序跑起来时,一般情况下,应用程序(application program)会时常通过API调用库里所预先备好的函数。但是有些库函数(library function)却要求应用先传给它一个函数,好在合适的时候调用,以完成目标任务。这个被传入的、后又被调用的函数就称为回调函数(callback function)。

打个比方,有一家旅馆提供叫醒服务,但是要求旅客自己决定叫醒的方法。可以是打客房电话,也可以是派服务员去敲门,睡得死怕耽误事的,还可以要求往自己头上浇盆水。这里,“叫醒”这个行为是旅馆提供的,相当于库函数,但是叫醒的方式是由旅客决定并告诉旅馆的,也就是回调函数。而旅客告诉旅馆怎么叫醒自己的动作,也就是把回调函数传入库函数的动作,称为**登记回调函数**(to register a callback function)。如下图所示(图片来源:维基百科):

可以看到,回调函数通常和应用处于同一抽象层(因为传入什么样的回调函数是在应用级别决定的)。而回调就成了一个高层调用底层,底层再过头来用高层的过程。(我认为)这应该是回调最早的应用之处,也是其得名如此的原因。

回调机制的优势

从上面的例子可以看出,回调机制提供了非常大的灵活性。请注意,从现在开始,我们把图中的库函数改称为中间函数了,这是因为回调并不仅仅用在应用和库之间。任何时候,只要想获得类似于上面情况的灵活性,都可以利用回调。

这种灵活性是怎么实现的呢?乍看起来,回调似乎只是函数间的调用,但仔细一琢磨,可以发现两者之间的一个关键的不同:在回调中,我们利用某种方式,把回调函数像参数一样传入中间函数。可以这么理解,在传入一个回调函数之前,中间函数是不完整的。换句话说,程序可以在运行时,通过登记不同的回调函数,来决定、改变中间函数的行为。这就比简单的函数调用要灵活太多了。请看下面这段Python写成的回调的简单示例:

[even.py](https://www.zhihu.com/search?q=even.py&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra={"sourceType"%3A"answer"%2C"sourceId"%3A27459821})
#回调函数1
#生成一个2k形式的偶数
def double(x):
    return x * 2
    
#回调函数2
#生成一个4k形式的偶数
def quadruple(x):
    return x * 4
callback_demo.py
from even import *

#中间函数
#接受一个生成偶数的函数作为参数
#返回一个奇数
def getOddNumber(k, getEvenNumber):
    return 1 + getEvenNumber(k)
    
#起始函数,这里是程序的主函数
def main():    
    k = 1
    #当需要生成一个2k+1形式的奇数时
    i = getOddNumber(k, double)
    print(i)
    #当需要一个4k+1形式的奇数时
    i = getOddNumber(k, quadruple)
    print(i)
    #当需要一个8k+1形式的奇数时
    i = getOddNumber(k, lambda x: x * 8)
    print(i)
    
if __name__ == "__main__":
    main()

运行callback_demp.py,输出如下:

3
5
9

上面的代码里,给getOddNumber传入不同的回调函数,它的表现也不同,这就是回调机制的优势所在。值得一提的是,上面的第三个回调函数是一个匿名函数。

易被忽略的第三方

通过上面的论述可知,中间函数和回调函数是回调的两个必要部分,不过人们往往忽略了回调里的第三位要角,就是中间函数的调用者。绝大多数情况下,这个调用者可以和程序的主函数等同起来,但为了表示区别,我这里把它称为起始函数(如上面的代码中注释所示)。

之所以特意强调这个第三方,是因为我在网上读相关文章时得到一种印象,很多人把它简单地理解为两个个体之间的来回调用。譬如,很多中文网页在解释“回调”(callback)时,都会提到这么一句话:“If you call me, I will call you back.”我没有查到这句英文的出处。我个人揣测,很多人把起始函数和回调函数看作为一体,大概有两个原因:第一,可能是“回调”这一名字的误导;第二,给中间函数传入什么样的回调函数,是在起始函数里决定的。实际上,回调并不是“你我”两方的互动,而是ABC的三方联动。有了这个清楚的概念,在自己的代码里实现回调时才不容易混淆出错。

另外,回调实际上有两种:阻塞式回调和延迟式回调。两者的区别在于:阻塞式回调里,回调函数的调用一定发生在起始函数返回之前;而延迟式回调里,回调函数的调用有可能是在起始函数返回之后。这里不打算对这两个概率做更深入的讨论,之所以把它们提出来,也是为了说明强调起始函数的重要性。网上的很多文章,提到这两个概念时,只是笼统地说阻塞式回调发生在主调函数返回之前,却没有明确这个主调函数到底是起始函数还是中间函数,不免让人糊涂,所以这里特意说明一下。另外还请注意,本文中所举的示例均为阻塞式回调。延迟式回调通常牵扯到多线程

  • 20
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Python回调函数是一种常见的技术,用于实现解耦合。回调函数是指将一个函数作为参数传递给另一个函数,并在特定事件发生时被调用。 回调函数的一个常见应用是事件驱动编程,其一个函数定义了某个事件的行为,而另一个函数作为回调函数在事件发生时被调用。 下面是一个简单的示例,演示了如何在Python使用回调函数来实现解耦合: ```python def event_handler(event, callback): # 执行某些事件处理操作 print("Event:", event) # 调用回调函数 callback() def my_callback(): # 回调函数的具体实现 print("Callback function is called") # 调用事件处理函数,并将回调函数作为参数传递 event_handler("button_click", my_callback) ``` 在上面的例子,`event_handler` 函数接受两个参数:`event` 表示事件的名称,`callback` 表示回调函数。在 `event_handler` 函数内部,我们可以执行一些特定的事件处理操作,然后调用传递的回调函数。 通过这种方式,我们可以将事件处理和具体的行为逻辑解耦合。`event_handler` 函数只负责处理事件,并在必要时调用回调函数。具体的行为逻辑由回调函数实现。 使用回调函数可以使代码更加灵活和可维护。可以根据具体需求定义不同的回调函数,而不需要修改事件处理函数的代码。 希望这个简单的示例能够帮助你理解如何在Python使用回调函数来实现解耦合。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wuxianfeng023

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值