此时执行到print a(10)。这个时候跳转到a=lambda y:y+x 此时的x=20,因此a(10)就等于20+10=30
从这上面的例子可以看出,尽管我们在lambda之前定义了x的值。但是最终的值并不是定义的时候就绑定,而是在实际lambda运行时才开始绑定。而在lambda实际运行也就是print a(10)的时候,x的值已经被赋值成了20. 如果想让参数在lambda定义的时候就固定,需要在定义的时候就设置参数的值 a=lambda y,x=x:y+x 在lambda中设置x=x,这样就将x的值绑定成了10这个值。 这个在列表推导的时候特别容易出错。如下面的代码。我们期望得到的是0,1,2,3,4 fun=[lambda x:x+n for n in range(5)]for f in fun: print f(0) 但是最终的结果却是4,4,4,4,4. 原因和之前的一样,n在被调用的时候被为4。 改成如下代码,n的值就可以每次都被绑定了。 fun=[lambda x,n=n:x+n for n in range(5)] partial使用: 如果函数的参数值太多,partial可以固定一个或多个参数的值,在调用的时候可以减少调用的参数个数。如下面的代码。固定d=3,在调用的时候只需要设置a,b,c的值 def spam(a,b,c,d): print a,b,c,d s1=partial(spam,d=3) s1(0,1,2) 来看一个实际的例子,假设你有一个点的列表来表示(x,y)坐标元组。你可以使用下面的函数来实现 points=[(1,2),(3,4),(5,6),(7,6)] def distance(p1,p2): x1,y1=p1 x2,y2=p2 return math.hypot(x2-x1,y2-y1) 但是如果我们想计算到某个基点的距离,并基于这个距离来进行排序。该如何操作呢。之前我们讲了lambda的用法。我们可以用lambda来实现,代码如下 points=[(1,2),(3,4),(5,6),(7,6)] pt=(4,3) ret=sorted(points,key=lambda points: math.hypot(pt[0]-points[0],pt[1]-points[1]))print ret 用lambda实现稍显冗余。Partial可以精简下代码。在这里我们将distance的第二个参数p2固定为pt。这样在调用的时候其实就不 ret=sorted(points,key=partial(distance,pt))print ret 这样在调用的时候其实就是下面的样式: distance((1,2),(4,3)) distance((3,4),(4,3)) distance((5,6),(4,3)) distance((7,6),(4,3)) 回调函数: 回调函数在C语言中经常使用,简单来说就是将回调函数的指针地址作为参数传递一个函数,而那个函数在需要用到的时候利用传递的地址回调函数。这时就可以利用这个机会在回调函数中处理或者完成操作。 比如下面的C语言代码。printWelcome的地址传递给(*print)(int).在callback中就可以调用
void printWelcome(int len)
{
printf("welcome -- %d/n", len);
}
void callback(int times, void (* print_info)(int))
{
int i;
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 resultdef add(x,y): return x+yif __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 resultdef delete(x,y): return x-ydef add(x,y): return x+yif __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 resultdef delete(x,y): return x-ydef add(x,y): return x+yif __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 内联回调函数: 首先来看下functools中wrap修饰器的用法。首先来看下 def decorator_try(func): def wrapper(*args,**kwargs): print 'call decorator_try' return func(*args,**kwargs) return wrapper @decorator_trydef example(): print 'call example' if __name__=='__main__': example() print example.__name__ 结果如下: E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter5.py call decorator_try call example wrapper 在这里example.__name__的结果是wrapper,而非example.也就是被修饰的函数的属性发生了改变。因为装饰器可以等效写成 example=decorator_try(example).而decorator_try的返回值是wrapper.因此example的属性也跟着变成了wrapper。要消除这样的影响,就要用到wraps 用wraps修饰一下wrapper后,得到的结果就是example def decorator_try(func): @wraps(func) def wrapper(*args,**kwargs): print 'call decorator_try' return func(*args,**kwargs) return wrapper E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter5.py call decorator_try call example example
转载于:https://www.cnblogs.com/zhanghongfeng/p/7151359.html