1. 接受任意数量参数的函数. 当传入函数的参数个数很多的时候,在函数定义的时候不需要为每一个参数定义一个变量,可以用*rest的方式来包含多余的参数。
  1. 如下面的代码,*rest包含了2,3,43个参数。且可以迭代访问。在这个例子中,rest其实就是其他位置参数组成的一个元组
  1. def avg(first,*rest):
  2.     for i in rest:
  3.         print i
  4.     average=(first+sum(rest))/(1+len(rest))
  5.     print average
  1. avg(1,2,3,4)
  1. 如果我们需要传递带关键字的参数:可以用下面的方法。当采用**attr的时候,attr其实是一个包含所有被传入进来的关键字参数的字典
  1. def avg(first,**attr):
  2.     for item in attr.items():
  3.         print item,attr[item[0]]
  1. avg(1,size='large',quantity=0)
  1. 得到的结果如下:
  1. E:\python2.7.11\python.exe E:/py_prj/python_cookbook.py
  1. ('quantity', 0) 0
  1. ('size', 'large') large
  1.  
  1. 如果想强制让某些参数用关键字参数传递,可以将强制关键字参数放到*参数后面或者单个的*后面
  1.  
  1. Lambda:
  1. C语言中,对于一些短小的实现。可以不用函数而是写一个宏的方式来实现。
  1. 比如#define M(y) y*y+3*y   那么M(5)最终的结果就是5*5+3*5=40
  1. python中也有类似的实现,这就是lambada。代码如下,这就是实现了一个加法的lambda
  1. add=lambda x,y:x+y
  2. print add(3,4)
  1. 再来看下面的这个例子:
  1. 我们想对name中的名字按照姓来进行排序。在sorted中指定key值也就是排序的依据。在这里用lambda name:name.split()[-1].lower()的方式将每个名字的姓提取出来,然后在赋值给key
  1. name=['David Beazley','Brains Jones','Raymond Hettinger','Ned Batchelder']
  2. ret=sorted(name,key=lambda name:name.split()[-1].lower())
  3. print ret
  1. 来看一个比较有意思的例子:
  1. x=10
  2. a=lambda y:y+x
  3. x=20
  4. b=lambda y:y+x
  1. print a(10)
  2. print b(10)
  1. 上面的代码a(10)和b(10)的值是多少,2030?直观上是对的,但是实际上结果却是3030. 为什么会这样呢。我们来单步运行下:
  1. 首先运行了a=lambda y:y+x 后,对应的x=10
  1. 在运行了b=lambda y:y+x后,对应的x=20

此时执行到print a(10)。这个时候跳转到a=lambda y:y+x 此时的x=20,因此a(10)就等于20+10=30

  1. 从这上面的例子可以看出,尽管我们在lambda之前定义了x的值。但是最终的值并不是定义的时候就绑定,而是在实际lambda运行时才开始绑定。而在lambda实际运行也就是print a(10)的时候,x的值已经被赋值成了20.
  1. 如果想让参数在lambda定义的时候就固定,需要在定义的时候就设置参数的值
  1. a=lambda y,x=x:y+x
  1. lambda中设置x=x,这样就将x的值绑定成了10这个值。
  1. 这个在列表推导的时候特别容易出错。如下面的代码。我们期望得到的是0,1,2,3,4
  1. fun=[lambda x:x+n for n in range(5)]
  2. for f in fun:
  3.     print f(0)
  1. 但是最终的结果却是4,4,4,4,4. 原因和之前的一样,n在被调用的时候被为4
  1. 改成如下代码,n的值就可以每次都被绑定了。
  1. fun=[lambda x,n=n:x+n for n in range(5)]
  1.  
  1. partial使用:
  1. 如果函数的参数值太多,partial可以固定一个或多个参数的值,在调用的时候可以减少调用的参数个数。如下面的代码。固定d=3,在调用的时候只需要设置a,b,c的值
  1. def spam(a,b,c,d):
  2.     print a,b,c,d
  1. s1=partial(spam,d=3)
  2. s1(0,1,2)
  1.  
  1. 来看一个实际的例子,假设你有一个点的列表来表示(x,y)坐标元组。你可以使用下面的函数来实现
  1. points=[(1,2),(3,4),(5,6),(7,6)]
  1.  
  1. def distance(p1,p2):
  2.     x1,y1=p1
  3.     x2,y2=p2
  4.     return math.hypot(x2-x1,y2-y1)
  1. 但是如果我们想计算到某个基点的距离,并基于这个距离来进行排序。该如何操作呢。之前我们讲了lambda的用法。我们可以用lambda来实现,代码如下
  1. points=[(1,2),(3,4),(5,6),(7,6)]
  2. pt=(4,3)
  3. ret=sorted(points,key=lambda points: math.hypot(pt[0]-points[0],pt[1]-points[1]))
  4. print ret
  1. lambda实现稍显冗余。Partial可以精简下代码。在这里我们将distance的第二个参数p2固定为pt。这样在调用的时候其实就不
  1. ret=sorted(points,key=partial(distance,pt))
  2. print ret
  1. 这样在调用的时候其实就是下面的样式:
  1. distance((1,2),(4,3))
  1. distance((3,4),(4,3))
  1. distance((5,6),(4,3))
  1. distance((7,6),(4,3))
  1.  
  1.  
  1.  
  1. 回调函数:
  1. 回调函数在C语言中经常使用,简单来说就是将回调函数的指针地址作为参数传递一个函数,而那个函数在需要用到的时候利用传递的地址回调函数。这时就可以利用这个机会在回调函数中处理或者完成操作。
  1. 比如下面的C语言代码。printWelcome的地址传递给(*print)(int).在callback中就可以调用

void printWelcome(int len)

{

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

}

  1.  

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);

}

  1. 我们通俗点来说,回调函数就好比你去商店买了东西,但是没货,这个时候你留了电话号码给店员,等到有货的时候店员打电话给你让你取取货。你的电话号码就相当于回调函数。
  1. 来看下python中的回调函数如何用:
  1. def apply_async(func,args,callback):
  2.     result=func(*args)
  3.     callback(result)
  4.  
  5. def print_result(result):
  6.     print result
  1. def add(x,y):
  2.     return x+y
  1. apply_async(add,(2,3),callback=print_result)
  1. apply_async中设置callbackprint_result.当add加法运行完以后,则可以调用print_result来打印。
  1. 有人会问,这和写中间函数有什么区别呢:代码改成如下不也是一样,在appy_async中调用print_result不是一样的么
  1. def apply_async(func,args):
  2.     result=func(*args)
  3.     print_result(result)
  4.  
  5. def print_result(result):
  6.     print result
  7.  
  8. def add(x,y):
  9.     return x+y
  10.  
  11. if __name__=='__main__':
  12.     apply_async(add,(2,3))
  1.  
  1. 确实这样写也是一样的效果,那么回调函数有什么好处呢?如果更新下我们的需求,在apply_async中我们还想打印出2个参数相减的结果。代码可以改成如下
  1. def apply_async(func,func1,args):
  2.     result=func(*args)
  3.     print_result(result)
  4.     result1=func1(*args)
  5.     print_result(result1)
  6.  
  7. def print_result(result):
  8.     print result
  9.  
  10. def delete(x,y):
  11.     return x-y
  12.  
  13. def add(x,y):
  14.     return x+y
  15.  
  16. if __name__=='__main__':
  17.     apply_async(add,delete,(2,3))
  1.  
  1. 但是如果需求继续增加,我们还想打印乘法,除法,幂运算等各种运算结果呢。这个时候在apply_async中不是得传递各种函数参数。参数越写愈多,也越来越不好看。这个时候回调函数的优势就体现出来了。
  1. def apply_async(func,args,callback):
  2.     result=func(*args)
  3.     callback(result)
  4.  
  5. def print_result(result):
  6.     print result
  7.  
  8. def delete(x,y):
  9.     return x-y
  10.  
  11. def add(x,y):
  12.     return x+y
  13.  
  14. if __name__=='__main__':
  15.     apply_async(add,(2,3),callback=print_result)
  16.     apply_async(delete,(2,3),callback=print_result)
  1.  
  1. 看到没,我只需要给apply_async的第一个参数传递不同的处理函数,我就可以得到不同的结果。而回调函数都是固定的。这就相当于将公共部分用回调函数来处理。而apply_async通过参数的传递得到了不同的结果。
  1. 在上面的回调函数中,回调函数只能处理传入的参数,无法访问其他变量。
  1. 为了让回调函数访问外部信息,有两种方法:1 使用一个绑定方法来代替一个简单函数
  1.  
  1. class ResultHandler:
  2.     def __init__(self):
  3.         self.sequence=0
  4.     def handler(self,result):
  5.         self.sequence+=1
  6.         print self.sequence,result
  1. r=ResultHandler()
  2. apply_async(add,(2,3),r.handler)
  3. apply_async(add,(4,4),r.handler)
  1.  
  1. 在这里首先创建类ResultHandler的实例,然后用handler来作为回调函数,这个时候就可以同步访问sequence这个变量
  1.  
  1. 第二种方法就是使用闭包。
  1. def make_handler():
  2.     sequence=0
  3.     def handler(result):
  4.         nonlocal sequence
  5.         sequence+=1
  6.         print sequence,result
  7.     return handler
  1. hanlder=make_handler()
  2. apply_async(add,(2,3),callback=hanlder)
  1.  
  1. 注意nonlocal是在Python3.0才使用的。在2.x是没有这个关键字的。因此在2.x中要么使用全局变量,要么使用列表或者字典。如果使用变量,会报错。因此系统不知道这个变量是在哪引用的。
  1. def make_handler():
  2.     sequence=[1]
  3.     def handler(result):
  4.         sequence[0]=2
  5.         print sequence,result
  6.     return handler
  1.  
  1.  
  1. 内联回调函数:
  1. 首先来看下functoolswrap修饰器的用法。首先来看下
  1. def decorator_try(func):
  2.     def wrapper(*args,**kwargs):
  3.         print 'call decorator_try'
  4.         return func(*args,**kwargs)
  5.     return wrapper
  6.  
  7.  
  8. @decorator_try
  9. def example():
  10.     print 'call example'
  11. if __name__=='__main__':
  12.     example()
  13.     print example.__name__
  1. 结果如下:
  1. E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter5.py
  1. call decorator_try
  1. call example
  1. wrapper
  1.  
  1. 在这里example.__name__的结果是wrapper,而非example.也就是被修饰的函数的属性发生了改变。因为装饰器可以等效写成 example=decorator_try(example).而decorator_try的返回值是wrapper.因此example的属性也跟着变成了wrapper。要消除这样的影响,就要用到wraps
  1. wraps修饰一下wrapper后,得到的结果就是example
  1. def decorator_try(func):
  2.     @wraps(func)
  3.     def wrapper(*args,**kwargs):
  4.         print 'call decorator_try'
  5.         return func(*args,**kwargs)
  6.     return wrapper
  1. E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter5.py
  1. call decorator_try
  1. call example
  1. example
  1.  
  1.  

python cookbook第三版学习笔记九:函数的更多相关文章

  1. python cookbook第三版学习笔记十:类和对象(一)

    类和对象: 我们经常会对打印一个对象来得到对象的某些信息. class pair:     def __init__(self,x,y):         self.x=x         self. ...

  2. python cookbook第三版学习笔记十九:未包装的函数添加参数

    比如有下面如下的代码,每个函数都需要判断debug的是否为True,而默认的debug为False def a(x,debug=False): if debug: print('calling a') ...

  3. python cookbook第三版学习笔记六:迭代器与生成器

    假如我们有一个列表 items=[1,2,3].我们要遍历这个列表我们会用下面的方式 For i in items:   Print i 首先介绍几个概念:容器,可迭代对象,迭代器 容器是一种存储数据 ...

  4. python cookbook第三版学习笔记 一

    数据结构 假设有M个元素的列表,需要从中分解出N个对象,N<M,这会导致分解的值过多的异常.如下: record=['zhf','zhf@163.com','775-555-1212','847 ...

  5. python cookbook第三版学习笔记十三:类和对象(三)描述器

    __get__以及__set__:假设T是一个类,t是他的实例,d是它的一个描述器属性.读取属性的时候T.d返回的是d.__get__(None,T),t.d返回的是d.__get__(t,T).说法 ...

  6. python cookbook第三版学习笔记二十:可自定义属性的装饰器

    在开始本节之前,首先介绍下偏函数partial.首先借助help来看下partial的定义 首先来说下第一行解释的意思: partial 一共有三个部分: (1)第一部分也就是第一个参数,是一个函数, ...

  7. python cookbook第三版学习笔记十六:抽象基类

    假设一个工程中有多个类,每个类都通过__init__来初始化参数.但是可能有很多高度重复且样式相同的__init__.为了减少代码.我们可以将初始化数据结构的步骤归纳到一个单独的__init__函数中 ...

  8. python cookbook第三版学习笔记十五:property和描述

    8.5 私有属性: 在python中,如果想将私有数据封装到类的实例上,有两种方法:1 单下划线.2 双下划线 1 单下划线一般认为是内部实现,但是如果想从外部访问的话也是可以的 2 双下划线是则无法 ...

  9. python cookbook第三版学习笔记七:python解析csv,json,xml文件

    CSV文件读取: Csv文件格式如下:分别有2行三列. 访问代码如下: f=open(r'E:\py_prj\test.csv','rb') f_csv=csv.reader(f) for f in ...

随机推荐

  1. C# 格式化 中文星期 显示

    最近有些小忙,直接贴代码吧, /// <summary> /// 获取系统的星期 /// </summary> /// <param name="dt" ...

  2. EasyMvc入门教程-基本控件说明(1)按钮

    按钮是我们最常用的控件之一了,先看下我们提供的按钮风格: 不同颜色的: 实现代码: @Html.Q().Button().Text("Danger").ColorDanger() ...

  3. 单选复选框的js代码取值

    单选框 复选框选中后的js代码处理 <script type="text/javascript"> function check(){ document.getElem ...

  4. 常用快递API及快递在线下单API分享

    1.常用快递API 支持顺丰.EMS.申通.圆通.韵达.汇通.中通.天天.德邦.全峰等主流快递公司. 文档地址:https://www.juhe.cn/docs/api/id/43 1.1常用快递查询 ...

  5. jquery 判断元素显示或隐藏

    $().is(":hidden"); $().is(":visible");

  6. DataTable行处理

    DataTable dt=new DataTable(); 新增行: DataRow addDR= mydatatable.NewRow();addDR["ID"] = " ...

  7. sprint3 【每日scrum】 TD助手站立会议第六天

    站立会议 组员 昨天 今天 困难 签到 刘铸辉 (组长) 在添加日程类型处添加了选择闹钟间隔多长时间相应,并写了闹钟运行的类 在日历各个事件上都增加闹钟显示,并将数据传递给日程和时间表 感觉跟楠哥在设 ...

  8. Source Insight 4.0 破解和使用

    参考出处: https://blog.csdn.net/u011604775/article/details/81698062 https://blog.csdn.net/user11223344ab ...

  9. python thrift hbase安装连接

    默认已装好 hbase,我的版本是hbase-0.98.24,并运行 python 2.7.x 步骤: sudo apt-get install automake bison flex g++ git ...

  10. cocos2d-x-3.1 国际化strings.xml解决乱码问题 (coco2d-x 学习笔记四)

    今天写程序的时候发现输出文字乱码,尽管在实际开发中把字符串写在代码里是不好的做法.可是有时候也是为了方便,遇到此问题第一时间在脑子里面联想到android下的strings.xml来做国际化.本文就仅 ...