什么是回调函数?
在python中一些变量都是对象,包括函数,函数名就是函数对象的变量名称,那么是否要将函数名变量做为参数传给其它函数呢? 答案是肯定的。
当函数B的函数名做为参数,传给别函数A时,并且A能够接受处理。 这样的函数B就是1个回调函数。
回调函数最初来自于C语言, 用函数指针做为另1个函数的参数,可以任意更改回调函数,只要这些函数参数数量与类型相同。 而python是把函数名做参数,相当于C++中的地址引用,主函数也可以更换回调函数。
现在,回调函数已成了1个编程的设计模式pattern, 在各类语言中都很流行。
回调函数的适用场景
回调函数主要用于对当前函数运行前,对数据进行预处理,如在图像识别的神经网络模型图片数据处理函数之前,可以通过回调函数对图片数据进行预处理,如统一图片尺寸,对图片命名进行规范化等操作。
或者处理大文件时,使用回调函数,避免读取两次,而且可以使用生成器,即使数据长度未知,也可以用回调函数。
所以正确地使用回调函数,可以提高代码的性能与可读性。
回调函数实例
需求: 对1个数据列表进行求和,求和之前,希望将对列表元素进行四舍五入,并剔除小于10,或大于65535的数据。 这里我们添加回调函数来进行数据清洗。
第1步,定义回调函数 clean_data()
def clean_data(input_list):
# 对列表元素四舍五入
xlist = list(map(lambda x: round(x), input_list))
# 对列表元素过滤
xlist = list(filter(lambda x: x > 10 and x < 65535, xlist))
print("回调函数处理后列表长度:", len(xlist))
return xlist
第2步,定义主函数 total(),最后1个参数为回调函数
注意,主函数的最后1个参数为回调函数名,其它参数个数及类型要与回调函数相同,否则会报错。 定义时的形参名不必与回调函数名称相同。
在主函数体内,使用回调函数进行数据清理, cb_data = cb(data)
def total(data, cb):
# 调用回调函数
cb_data = cb(data)
return reduce(lambda x, y: x+y, cb_data)
第3步 实际调用主函数
将回调函数名做为实参传入total() 函数,
print("列表数值总和: ", total(demo_data, clean_data))
运行程序,输出为:
原始列表长度: 100
回调函数处理后列表长度: 95
列表数值总和: 3223626
可以看出, total 调用了clean_data() , 而且 total定义时使用的参数名称为cb, 而不是clean_data. 所以你还可以更换、修改回调函数来添加新功能,而不需要改动主函数的代码,这的确很方便。
完整代码
# 验证 call back 回调函数
import random
from functools import reduce
def clean_data(input_list):
# 对列表元素四舍五入
xlist = list(map(lambda x: round(x), input_list))
# 对列表元素过滤
xlist = list(filter(lambda x: x > 10 and x < 65535, xlist))
print("回调函数处理后列表长度:", len(xlist))
return xlist
def total(data, cb):
# 调用回调函数
cb_data = cb(data)
return reduce(lambda x, y: x+y, cb_data)
demo_data = [random.uniform(1, 70000) for i in range(0, 100)]
print("原始列表长度:", len(demo_data))
print("列表数值总和: ", total(demo_data, clean_data))