回调函数(真好理解)(精选7篇)由网友“彼鲨泥蝶”投稿提供,下面是小编为大家整理后的回调函数(真好理解),如果喜欢可以分享给身边的朋友喔!
篇1:回调函数(真好理解)
回调函数
在看LWIP时,见到用回调函数,再看某老外公司OPC源代码时,见到用回调函数,看我国内某些代码(我公司软件等)时没用到。于是,我对回调函数产生了很大的好奇。以前,我写VC程序时用到过回调函数,但是没有用C语言来使用。最近,看到国外大量的经典代码中广泛使用了回调函数(LWIP、某两个公司的OPC程序等),都是C语言来实现的,而不是VC windows程序中别人实现自己使用的那种。
为了弄明白这种函数的奥妙,首先提出三个问题:
1. 回调函数是什么东西?
2. 回调函数怎么开发,怎么使用?
3. 回调函数的作用,应该在什么情况下使用?
带着问题来学习,有目的!呵呵,个人经验。
打开baidu.com、google.cn搜索了好多资料,如下:
顺便提一下,某君的一个签名很让我佩服:1好好活着,因为我们会死很久。2五千年的文明 两百年的无奈
第一个问题:
*******************************************************************************
其实回调就是一种利用函数指针进行函数调用的过程.
为什么要用回调呢?比如我要写一个子模块给你用, 来接收远程socket发来的命令.当我接收到命令后, 需要调用你的主模块的函数, 来进行相应的处理.但是我不知道你要用哪个函数来处理这个命令, 我也不知道你的主模块是什么.cpp或者.h, 或者说, 我根本不用关心你在主模块里怎么处理它, 也不应该关心用什么函数处理它...... 怎么办?
使用回调!
—— lone wolf
使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个函数。而那个函数在需要的时候,利用传递的地址调用回调函数,这时你可以利用这个机会在回调函数中处理消息或完成一定的操作。
—— 某专家
回调函数,就是由你自己写的。你需要调用另外一个函数,而这个函数的其中一个参数,就是你的这个回调函数名。这样,系统在必要的时候,就会调用你写的回调函数,这样你就可以在回调函数里完成你要做的事。
—— 绿叶
hi.baidu.com/zhuyipeng/blog/item/863fefdb7c736c63d1164eec.html 是一篇比较好的文章。
什么是回调函数?
回调函数是应用程序提供给Windows系统DLL或其它DLL调用的函数,一般用于截获消息、获取系统信息或处理异步事件。应用程序把回调函数的地址指针告诉DLL,而DLL在适当的时候会调用该函数。回调函数必须遵守事先规定好的参数格式和传递方式,否则DLL一调用它就会引起程序或系统的崩溃。通常情况下,回调函数采用标准WindowsAPI的调用方式,即__stdcall,当然,DLL编制者可以自己定义调用方式,但客户程序也必须遵守相同的规定。在__stdcall方式下,函数的参数按从右到左的顺序压入堆栈,除了明确指明是指针或引用外,参数都按值传递,函数返回之前自己负责把参数从堆栈中弹出。
理解回调函数!
—— jufengfeng
Function Pointers provide the concept of callback functions.
—— newty.de
*******************************************************************************
看了这么多的资料,我只将每位的定义总结一下就一句话:回调函数就是函数指针的一种用法,
在部分资料上,大量讨论了回调函数怎么被调用,到底被谁调用,还有好多的图形,我认为都没有看到问题的本质。
第二个问题:
*********************************************************************
我实现了一个很简单的回调函数。
#include
void printWelcome(int len)
{
printf(“欢迎欢迎 -- %d/n”, len);
}
void printGoodbye(int len)
{
printf(“送客送客 -- %d/n”, len);
}
void callback(int times, void (* print)(int))
{
int i;
for (i = 0; i < times; ++i)
{
print(i);
}
printf(“/n我不知道你是迎客还是送客!/n/n”);
}
void main(void)
{
callback(10, printWelcome);
callback(10, printGoodbye);
printWelcome(5);
}
*******************************************************************************
上面的代码没有被任何系统函数调用,说明那些东西只是撒撒土迷迷路人眼而已。还有面相对象编程时,用class给封装起来也是掩人耳目,不要被外表所迷惑。
第三个问题:
*********************************************************************
用过STL的人都知道,在STL中众多算法和程序都用到回调函数,这实现了一种策略。只要任何符合我的标准的函数和计算都可以用我这个公式。你可以实现各种各样的回调函数,只要符合我的格式就能用。
就上面的程序来说,你只要函数格式符合cllback第二个参数的格式不论你给别人做饭、铺床叠被都可以正常工作。这就是回调的作用,把回调实现留给别人。
这是一个用法。
有一位朋友用分层的概念来解释了回调机制:callback函数为B层,main函数和print*函数为A层,A层调用了B层的回调函数callmeback,而B层的回调函数调用了A层的实现函数print*。说白了B层就是一个接口。
这是我的理解。Over!
转自:blog.csdn.net/callmeback/article/details/4242260
篇2:Python回调函数用法实例详解
作者:tianmo 字体:[增加 减小] 类型:
这篇文章主要介绍了Python回调函数用法,以实例形式较为详细的分析了Python回调函数的定义、功能及相关使用技巧,需要的朋友可以参考下
本文实例讲述了Python回调函数用法,分享给大家供大家参考。具体分析如下:
一、百度百科上对回调函数的解释:
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
二、什么是回调:
软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用;回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。回调和异步调用的关系非常紧密,通常我们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。同步调用是三者当中最简单的,而回调又常常是异步调用的基础,因此,下面我们着重讨论回调机制在不同软件架构中的实现。
三、一个小例子:
#call.py import called def callback: print “in callback” def main(): #called.test() called.test_call(callback) print “in call.py” main() #called.py ‘‘‘‘‘ def test(): print “in called.py test()” ‘‘‘ def test_call(p_call): print “in called.py test_call()” p_call() joe@joe:~/test/python$ python call.py in called.py test_call() in callback in call.py joe@joe:~/test/python$
网上搜到的一个面向对象实现的例子:
当你要加入回调(Callback)功能的时候,代码往往会偏重于回调的实现而不是问题本身了。一个解决方法就是实现一个通用的基础类来解决回调的需求,然后再来实现你为某个事件(Event)所绑定(Binding)的方法(Method)。
代码如下:
class CallbackBase: def __init__(self): self.__callbackMap = {} for k in (getattr(self, x) for x in dir(self)): if hasattr(k, “bind_to_event”): self.__callbackMap.setdefault(k.bind_to_event, []).append(k) elif hasattr(k, “bind_to_event_list”): for j in k.bind_to_event_list: self.__callbackMap.setdefault(j, []).append(k) ## staticmethod is only used to create a namespace @staticmethod def callback(event): def f(g, ev = event): g.bind_to_event = ev return g return f @staticmethod def callbacklist(eventlist): def f(g, evl = eventlist): g.bind_to_event_list = evl return g return f def dispatch(self, event): l = self.__callbackMap[event] f = lambda *args, **kargs: map(lambda x: x(*args, **kargs), l) return f ## Sample class MyClass(CallbackBase): EVENT1 = 1 EVENT2 = 2 @CallbackBase.callback(EVENT1) def handler1(self, param = None): print “handler1 with param: %s” % str(param) return None @CallbackBase.callbacklist([EVENT1, EVENT2]) def handler2(self, param = None): print “handler2 with param: %s” % str(param) return None def run(self, event, param = None): self.dispatch(event)(param) if __name__ == “__main__”: a = MyClass() a.run(MyClass.EVENT1, ‘mandarina‘) a.run(MyClass.EVENT2, ‘naranja‘)
这里有一个类,它有两个事件(EVENT1和EVENT2)和两个处理函数(handler),
第一个处理函数handler1注册了EVENT1,而第二个处理函数handler2当EVENT1或者EVENT2发生的时候都会执行(即注册了全部的事件)。
运行函数(run)在MyClass的主循环中,它会将对应的事件派送(dispatch)出去。这(这里指dispatch函数)会返回一个函数,我们可以把所有需要传给这个函数的参数列表传给它。这个函数运行结束会返回一个列表(list),列表中是所有的返回值。
也许,使用Metaclass能够实现的更优雅一些吧。
希望本文所述对大家的Python程序设计有所帮助。
篇3:函数的值域定义及理解
对函数值域的理解:
(1)函数的值域与最值均是在定义域上研究的,闭区间上的.连续函数必有最大值和最下值;
(2)函数值域的几何意义是函数图像上点的纵坐标的变化范围。
篇4:回调函数应用(冒泡排序 既排整型数组 也可排字符串
题目:回调函数实现冒泡排序 排整数也可排字符串 n为数组元素大小
#define _CRT_SECURE_NO_WARNINGS 1#include 作者:廖雪峰 字体:[增加 减小] 类型: 这篇文章主要介绍了Python中函数的参数,掌握函数中的参数传递在任何一门语言的学习过程当中都是基本功,需要的朋友可以参考下 定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了,对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数内部的复杂逻辑被封装起来,调用者无需了解。 Python的函数定义非常简单,但灵活度却非常大。除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代码。 默认参数 我们仍以具体的例子来说明如何定义函数的默认参数。先写一个计算x2的函数: def power(x): return x * x 当我们调用power函数时,必须传入有且仅有的一个参数x: >>> power(5)25>>> power(15)225 现在,如果我们要计算x3怎么办?可以再定义一个power3函数,但是如果要计算x4、x5……怎么办?我们不可能定义无限多个函数。 你也许想到了,可以把power(x)修改为power(x, n),用来计算xn,说干就干: def power(x, n): s = 1 while n > 0: n = n - 1 s = s * x return s 对于这个修改后的power函数,可以计算任意n次方: >>> power(5, 2)25>>> power(5, 3)125 但是,旧的调用代码失败了,原因是我们增加了一个参数,导致旧的代码无法正常调用: >>> power(5)Traceback (most recent call last): File “ 这个时候,默认参数就排上用场了。由于我们经常计算x2,所以,完全可以把第二个参数n的默认值设定为2: def power(x, n=2): s = 1 while n > 0: n = n - 1 s = s * x return s 这样,当我们调用power(5)时,相当于调用power(5, 2): >>> power(5)25>>> power(5, 2)25 而对于n > 2的其他情况,就必须明确地传入n,比如power(5, 3)。 从上面的例子可以看出,默认参数可以简化函数的调用。设置默认参数时,有几点要注意: 一是必选参数在前,默认参数在后,否则Python的解释器会报错(思考一下为什么默认参数不能放在必选参数前面); 二是如何设置默认参数。 当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数。 使用默认参数有什么好处?最大的好处是能降低调用函数的难度。 举个例子,我们写个一年级小学生注册的函数,需要传入name和gender两个参数: def enroll(name, gender): print ‘name:‘, name print ‘gender:‘, gender 这样,调用enroll()函数只需要传入两个参数: >>> enroll(‘Sarah‘, ‘F‘)name: Sarahgender: F 如果要继续传入年龄、城市等信息怎么办?这样会使得调用函数的复杂度大大增加。 我们可以把年龄和城市设为默认参数: def enroll(name, gender, age=6, city=‘Beijing‘): print ‘name:‘, name print ‘gender:‘, gender print ‘age:‘, age print ‘city:‘, city 这样,大多数学生注册时不需要提供年龄和城市,只提供必须的两个参数: >>> enroll(‘Sarah‘, ‘F‘)Student:name: Sarahgender: Fage: 6city: Beijing 只有与默认参数不符的学生才需要提供额外的信息: enroll(‘Bob‘, ‘M‘, 7)enroll(‘Adam‘, ‘M‘, city=‘Tianjin‘) 可见,默认参数降低了函数调用的难度,而一旦需要更复杂的调用时,又可以传递更多的参数来实现。无论是简单调用还是复杂调用,函数只需要定义一个。 有多个默认参数时,调用的时候,既可以按顺序提供默认参数,比如调用enroll(‘Bob‘, ‘M‘, 7),意思是,除了name,gender这两个参数外,最后1个参数应用在参数age上,city参数由于没有提供,仍然使用默认值。 也可以不按顺序提供部分默认参数。当不按顺序提供部分默认参数时,需要把参数名写上。比如调用enroll(‘Adam‘, ‘M‘, city=‘Tianjin‘),意思是,city参数用传进去的值,其他默认参数继续使用默认值。 默认参数很有用,但使用不当,也会掉坑里。默认参数有个最大的坑,演示如下: 先定义一个函数,传入一个list,添加一个END再返回: def add_end(L=[]): L.append(‘END‘) return L 当你正常调用时,结果似乎不错: >>> add_end([1, 2, 3])[1, 2, 3, ‘END‘]>>> add_end([‘x‘, ‘y‘, ‘z‘])[‘x‘, ‘y‘, ‘z‘, ‘END‘] 当你使用默认参数调用时,一开始结果也是对的: >>> add_end()[‘END‘] 但是,再次调用add_end()时,结果就不对了: >>> add_end()[‘END‘, ‘END‘]>>> add_end()[‘END‘, ‘END‘, ‘END‘] 很多初学者很疑惑,默认参数是[],但是函数似乎每次都“记住了”上次添加了‘END‘后的list。 原因解释如下: Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是一个变量,它指向对象[],每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。 所以,定义默认参数要牢记一点:默认参数必须指向不变对象! 要修改上面的例子,我们可以用None这个不变对象来实现: def add_end(L=None): if L is None: L = [] L.append(‘END‘) return L 现在,无论调用多少次,都不会有问题: >>> add_end()[‘END‘]>>> add_end()[‘END‘] 为什么要设计str、None这样的不变对象呢?因为不变对象一旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误, 此外,由于对象不变,多任务环境下同时读取对象不需要加锁,同时读一点问题都没有。我们在编写程序时,如果可以设计一个不变对象,那就尽量设计成不变对象。 可变参数 在Python函数中,还可以定义可变参数。顾名思义,可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个。 我们以数学题为例子,给定一组数字a,b,c……,请计算a2 + b2 + c2 + ……。 要定义出这个函数,我们必须确定输入的参数。由于参数个数不确定,我们首先想到可以把a,b,c……作为一个list或tuple传进来,这样,函数可以定义如下: def calc(numbers): sum = 0 for n in numbers: sum = sum + n * n return sum 但是调用的时候,需要先组装出一个list或tuple: >>> calc([1, 2, 3])14>>> calc((1, 3, 5, 7))84 如果利用可变参数,调用函数的方式可以简化成这样: >>> calc(1, 2, 3)14>>> calc(1, 3, 5, 7)84 所以,我们把函数的参数改为可变参数: def calc(*numbers): sum = 0 for n in numbers: sum = sum + n * n return sum 定义可变参数和定义list或tuple参数相比,仅仅在参数前面加了一个*号。在函数内部,参数numbers接收到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数: >>> calc(1, 2)5>>> calc()0 如果已经有一个list或者tuple,要调用一个可变参数怎么办?可以这样做: >>> nums = [1, 2, 3]>>> calc(nums[0], nums[1], nums[2])14 这种写法当然是可行的,问题是太繁琐,所以Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去: >>> nums = [1, 2, 3]>>> calc(*nums)14 这种写法相当有用,而且很常见。 关键字参数 可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。请看示例: def person(name, age, **kw): print ‘name:‘, name, ‘age:‘, age, ‘other:‘, kw 函数person除了必选参数name和age外,还接受关键字参数kw。在调用该函数时,可以只传入必选参数: >>> person(‘Michael‘, 30)name: Michael age: 30 other: {} 也可以传入任意个数的关键字参数: >>> person(‘Bob‘, 35, city=‘Beijing‘)name: Bob age: 35 other: {‘city‘: ‘Beijing‘}>>> person(‘Adam‘, 45, gender=‘M‘, job=‘Engineer‘)name: Adam age: 45 other: {‘gender‘: ‘M‘, ‘job‘: ‘Engineer‘} 关键字参数有什么用?它可以扩展函数的功能。比如,在person函数里,我们保证能接收到name和age这两个参数,但是,如果调用者愿意提供更多的参数,我们也能收到。试想你正在做一个用户注册的功能,除了用户名和年龄是必填项外,其他都是可选项,利用关键字参数来定义这个函数就能满足注册的需求。 和可变参数类似,也可以先组装出一个dict,然后,把该dict转换为关键字参数传进去: >>> kw = {‘city‘: ‘Beijing‘, ‘job‘: ‘Engineer‘}>>> person(‘Jack‘, 24, city=kw[‘city‘], job=kw[‘job‘])name: Jack age: 24 other: {‘city‘: ‘Beijing‘, ‘job‘: ‘Engineer‘} 当然,上面复杂的调用可以用简化的写法: >>> kw = {‘city‘: ‘Beijing‘, ‘job‘: ‘Engineer‘}>>> person(‘Jack‘, 24, **kw)name: Jack age: 24 other: {‘city‘: ‘Beijing‘, ‘job‘: ‘Engineer‘} 参数组合 在Python中定义函数,可以用必选参数、默认参数、可变参数和关键字参数,这4种参数都可以一起使用,或者只用其中某些,但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数和关键字参数。 比如定义一个函数,包含上述4种参数: def func(a, b, c=0, *args, **kw): print ‘a =‘, a, ‘b =‘, b, ‘c =‘, c, ‘args =‘, args, ‘kw =‘, kw 在函数调用的时候,Python解释器自动按照参数位置和参数名把对应的参数传进去。 >>> func(1, 2)a = 1 b = 2 c = 0 args = () kw = {}>>> func(1, 2, c=3)a = 1 b = 2 c = 3 args = () kw = {}>>> func(1, 2, 3, ‘a‘, ‘b‘)a = 1 b = 2 c = 3 args = (‘a‘, ‘b‘) kw = {}>>> func(1, 2, 3, ‘a‘, ‘b‘, x=99)a = 1 b = 2 c = 3 args = (‘a‘, ‘b‘) kw = {‘x‘: 99} 最神奇的是通过一个tuple和dict,你也可以调用该函数: >>> args = (1, 2, 3, 4)>>> kw = {‘x‘: 99}>>> func(*args, **kw)a = 1 b = 2 c = 3 args = (4,) kw = {‘x‘: 99} 所以,对于任意函数,都可以通过类似func(*args, **kw)的形式调用它,无论它的参数是如何定义的。 小结 Python的函数具有非常灵活的参数形态,既可以实现简单的调用,又可以传入非常复杂的参数。 默认参数一定要用不可变对象,如果是可变对象,运行会有逻辑错误! 要注意定义可变参数和关键字参数的语法: *args是可变参数,args接收的是一个tuple; **kw是关键字参数,kw接收的是一个dict。 以及调用函数时如何传入可变参数和关键字参数的语法: 可变参数既可以直接传入:func(1, 2, 3),又可以先组装list或tuple,再通过*args传入:func(*(1, 2, 3)); 关键字参数既可以直接传入:func(a=1, b=2),又可以先组装dict,再通过**kw传入:func(**{‘a‘: 1, ‘b‘: 2})。 使用*args和**kw是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。 被人理解的感觉真好 “你真让我失望,考了这么点分还敢回家,我都为你丢脸啊!”楼上又一次响起了无休止的漫骂声。 楼上的姐姐学习真的非常用功,可是却偶尔不能达到理想的成绩。那个阿姨就把她说得一无是处。相比之下,我又回想起那一次,忽然觉得自己好幸福,被家人理解的感觉真好。 那天,冰冷的雨水伴着我走在回家的路上,那雨水一滴滴落在我身上,却感觉像一颗颗子弹砸在我心上。耳边又响起了那个冰冷的声音:“,77分。”我不知道该怎么给妈妈交代,那个慈祥温柔的面孔会不会以暴风雨来代替?忐忑不安的我不知不觉走到了家门口,想要敲门的手犹犹豫豫地放了下来。但是不管怎样也要面对呀!一手擦干净已被泪花完全占据的脸,一手 “咚咚咚”地敲来了门。“妈妈,我回来了!”“快进来,今天你回来晚了,饭菜都凉了,你先写作业,我去把饭菜热一下!” 看者妈妈疲倦的背影,我又一次泪眼模糊。“妈妈,我轻轻的叫了一声,不要热了,我就这样吃吧!”妈妈似乎看出了我的泪痕,忙问我:“是不是哭了,为什么呀?”含着的眼泪再也忍不住了,随着我心里的难受一起释放了出来。妈妈还是像往常一样笑了笑:“别说了,先去吃饭吧!”我顺从的点点头。心情不好,饭也吃的很少,家里少有的沉默就像一张巨大的黑暮笼罩在头顶上。妈妈,你骂我一顿吧!也许那样我会好受些。“孩子,别灰心,妈妈这次不会说你什么,我知道是你自己没有努力,对吗?妈妈理解你,一张试卷不能带边一生。它只是一个转弯,你可能这次碰壁,但下一次我相信你会做好的!” 这时心理有了那种少有的自信,妈妈的话又让我激起了斗志,我暗暗记下妈妈的话,给自己加油。妈妈给予我的不是财宝,确实精神上的一笔无价的财富,我终生记住它的名称----理解。 我对楼上的那位姐姐充满了同情,我多想告诉她:“我们的生活充满了七色阳光,即使是在阳光普照的时候,也难免出现短暂的阴云。一定不要灰心丧气”好多人没有那种感受,但是告诉你----被人理解的感觉真好! 一个检测OpenSSL心脏出血漏洞的Python脚本 Python 命令行参数sys.argv python判断端口是否打开的实现代码 python 域名分析工具实现代码 wxpython学习笔记(推荐查看) python操作数据库之sqlite3打开数据库、删 PHP webshell检查工具 python实现代码 python list中append()与extend()用法分享 python写的一个文本编辑器 python实现倒计时的示例 Python入门教程 超详细1小时学会 python 中文乱码问题深入分析 比较详细Python正则表达式操作指 Python字符串的encode与decode研 Python open读写文件实现脚本 Python enumerate遍历数组示例应 Python 深入理解yield Python+Django在windows下的开发 python 文件和路径操作函数小结 python 字符串split的用法分享 【回调函数(真好理解)(精选7篇)】相关文章: 软件工程教学总结2023-11-22 python实现中文分词FMM算法实例2023-05-16 软件工程总结2022-05-07 HTML前端开发面试题及前端知识2023-03-28 二数下册教学计划2023-04-02 ORIMA空三加密软件在铁路航测中的应用与开发2022-04-29 web前端面试题2022-11-11 电气工程师面试题2022-05-08 因纳特模拟实践报告2022-11-10 软件年终总结2022-08-03篇5:理解Python中函数的参数
篇6:被人理解的感觉真好
篇7:python实现异步回调机制代码
最近更 新
热 点 排 行