转自: 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:
当从另一个函数调用一个函数时,它被称为回调函数。回调函数是作为参数传递给另一个函数的函数。这可以通过两种方式实现:
- Passing one function as an argument to another function将一个函数作为参数传递给另一个函数
- 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的三方联动。有了这个清楚的概念,在自己的代码里实现回调时才不容易混淆出错。
另外,回调实际上有两种:阻塞式回调和延迟式回调。两者的区别在于:阻塞式回调里,回调函数的调用一定发生在起始函数返回之前;而延迟式回调里,回调函数的调用有可能是在起始函数返回之后。这里不打算对这两个概率做更深入的讨论,之所以把它们提出来,也是为了说明强调起始函数的重要性。网上的很多文章,提到这两个概念时,只是笼统地说阻塞式回调发生在主调函数返回之前,却没有明确这个主调函数到底是起始函数还是中间函数,不免让人糊涂,所以这里特意说明一下。另外还请注意,本文中所举的示例均为阻塞式回调。延迟式回调通常牵扯到多线程