python cookbook学习笔记十五:回调函数(1)

时间:2022-01-20 16:06:16
回调函数在C语言中经常使用,简单来说就是将回调函数的指针地址作为参数传递一个函数,而那个函数在需要用到的时候利用传递的地址回调函数。这时就可以利用这个机会在回调函数中处理或者完成操作。
比如下面的C语言代码。printWelcome的地址传递给(*print)(int).在callback中就可以调用

void printWelcome(intlen)

{

       printf("welcome -- %d/n",len);

}

 

void callback(inttimes, void (* print_info)(int))

{

       inti;

       for(i = 0; i < times; ++i)

       {

              Print_info(i);

       }

void main(void)

{

       callback(10,printWelcome);

}

我们通俗点来说,回调函数就好比你去商店买了东西,但是没货,这个时候你留了电话号码给店员,等到有货的时候店员打电话给你让你取取货。你的电话号码就相当于回调函数。
来看下python中的回调函数如何用:
def apply_async(func,args,callback):
    result=func(*args)
    callback(result)

def print_result(result):
    print result
def add(x,y):
    return x+y
apply_async(add,(2,3),callback=print_result)
在apply_async中设置callback为print_result.当add加法运行完以后,则可以调用print_result来打印。
有人会问,这和写中间函数有什么区别呢:代码改成如下不也是一样,在appy_async中调用print_result不是一样的么
def apply_async(func,args):
    result=func(*args)
    print_result(result)

def print_result(result):
    print result

def add(x,y):
    return x+y

if __name__=='__main__':
    apply_async(add,(2,3))
 
确实这样写也是一样的效果,那么回调函数有什么好处呢?如果更新下我们的需求,在apply_async中我们还想打印出2个参数相减的结果。代码可以改成如下
def apply_async(func,func1,args):
    result=func(*args)
    print_result(result)
    result1=func1(*args)
    print_result(result1)

def print_result(result):
    print result

def delete(x,y):
    return x-y

def add(x,y):
    return x+y

if __name__=='__main__':
    apply_async(add,delete,(2,3))
 
但是如果需求继续增加,我们还想打印乘法,除法,幂运算等各种运算结果呢。这个时候在apply_async中不是得传递各种函数参数。参数越写愈多,也越来越不好看。这个时候回调函数的优势就体现出来了。
def apply_async(func,args,callback):
    result=func(*args)
    callback(result)

def print_result(result):
    print result

def delete(x,y):
    return x-y

def add(x,y):
    return x+y

if __name__=='__main__':
    apply_async(add,(2,3),callback=print_result)
    apply_async(delete,(2,3),callback=print_result)
 
看到没,我只需要给apply_async的第一个参数传递不同的处理函数,我就可以得到不同的结果。而回调函数都是固定的。这就相当于将公共部分用回调函数来处理。而apply_async通过参数的传递得到了不同的结果。
 
在上面的回调函数中,回调函数只能处理传入的参数,无法访问其他变量。
为了让回调函数访问外部信息,有两种方法:1 使用一个绑定方法来代替一个简单函数
 
class ResultHandler:
    def __init__(self):
        self.sequence=0
   
def handler(self,result):
        self.sequence+=1
       
print self.sequence,result
r=ResultHandler()
apply_async(add,(2,3),r.handler)
apply_async(add,(4,4),r.handler)
 
在这里首先创建类ResultHandler的实例,然后用handler来作为回调函数,这个时候就可以同步访问sequence这个变量
 
第二种方法就是使用闭包。
def make_handler():
    sequence=0
   
def handler(result):
        nonlocal sequence
        sequence+=1
       
print sequence,result
    return handler
hanlder=make_handler()
apply_async(add,(2,3),callback=hanlder)
 
注意nonlocal是在Python3.0才使用的。在2.x是没有这个关键字的。因此在2.x中要么使用全局变量,要么使用列表或者字典。如果使用变量,会报错。因此系统不知道这个变量是在哪引用的。
def make_handler():
    sequence=[1]
    def handler(result):
        sequence[0]=2
       
print sequence,result
    return handler