Python基础-函数[2]
来源:互联网 发布:广东粤数大数据忽悠 编辑:程序博客网 时间:2024/06/10 06:51
函数嵌套
在一个函数定义中再定义一个函数 def outfunc(): def infunc(): expression
返回一个函数:
格式:
1234
def outfunc(): def infunc(): expression return infunc
eg:
1234567891011121314151617
#!/usr/bin/env python# coding=utf-8def outfunc(): print 'this is calling outfunc.....' def infunc(): print 'this is calling infunc....' return infuncf = outfunc() #这里返回infunc函数f()=========结果==========root@tonglele /code/Python/function/test # python code1.pythis is calling outfunc.....this is calling infunc....
此时我们举一个例子:例如,我们现在想测试一个函数的运行时间,但又不破坏这个函数,不给这个函数增加代码,我们该怎样做?
12345678910111213141516171819202122232425262728
#!/usr/bin/env python# coding=utf-8import timeimport datetimedef func(arg): time.sleep(arg)def timeIt(func): def warp(arg): start = datetime.datetime.now() func(arg) end = datetime.datetime.now() cost = end - start print "execute %s spend %s" % (func.__name__,cost.total_seconds()) return warpnew_func = timeIt(func) #此时timeIt返回一个新的函数warpnew_func(3) #调用新的函数,并传值进去=========运行结果===========root@tonglele /code/Python/function/test # python code2.pyexecute func spend 3.003061
这样我们便使用了一种非入侵的方式包装了这个函数,并且增加了我们需要的功能,这就是Python中的装饰器。
装饰器
12345678910111213141516171819202122232425262728
#!/usr/bin/env python# coding=utf-8import timeimport datetimedef timeIt(func): def warp(arg): start = datetime.datetime.now() func(arg) end = datetime.datetime.now() cost = end - start print "execute %s spend %s" % (func.__name__,cost.total_seconds()) return warp@timeIt #此时,func函数被timeIt装饰器包装def func(arg): print func.__name__ time.sleep(arg)func(3)============运行结果=========root@tonglele /code/Python/function/test # python code2.pywarp #此时func.__name__返回的名字不再是‘func’了,而是被装饰器改变成了warp。如果想要保留原来的__name__,__doc__等元信息,需要做如下修改。execute func spend 3.003148
1234567891011121314151617181920212223242526
#!/usr/bin/env python# coding=utf-8import timeimport datetimeimport functoolsdef timeIt(func): @functools.wraps(func) #增加这一行,将原函数作为值传进去,表示将原函数的__name__,__moudle__,__doc__等信息更新到装饰器里 def warp(arg): start = datetime.datetime.now() func(arg) end = datetime.datetime.now() cost = end - start print "execute %s spend %s" % (func.__name__,cost.total_seconds()) return warp@timeItdef func(arg): print func.__name__ time.sleep(arg)func(3)
lambda匿名函数
Python使用lambda关键字创造匿名函数。匿名,即不再用def语句这样的标准形式定义一个函数。
这种语句的目的是由于性能原因,在调用时绕过函数的栈分配
语法为:lambda [arg1[,arg2,...argN]]:expression
其中,参数是可选的,如果使用参数的话,参数通常也会在表达式中出现
lambda语句的使用方法(无参数)
12345
>>> lambda:1<function <lambda> at 0x7f02d5f3f398>>>> f = lambda:1 #lambda会返回一个函数,将该函数赋值给变量f>>> f()1
lambda语句的使用方法(有参数)
12345678910111213
>>> f = lambda x,y:x+y>>> f(2,3)5>>> f = lambda x,y = 10:x+y #带默认值参数>>> f(2)12>>> f(19,20)39>>> f = lambda *x:map(lambda x:x + 10,x) #可变位置参数>>> f(1,2,3,4)[11, 12, 13, 14]>>> f(*[2,3,4,5,6])[12, 13, 14, 15, 16]
一个计算器的例子
123456789101112131415161718192021
#!/usr/bin/env python# coding=utf-8func = { "add":lambda x,y : x + y, "sub":lambda x,y : x - y, "mul":lambda x,y : x * y, "div":lambda x,y : x / y}print func["add"](3,4)print func["sub"](3,4)print func["mul"](3,4)print func["div"](3,4)=============运行结果======root@tonglele /code/Python/function/test # python code3.py7-1120
generator生成器
与列表解析语法类似,只不过把列表解析的[]换成了()
生成器表达式能做的事,列表解析基本都能处理,只不过在需要处理的序列比较大时,列表解析比较费内存
简单的生成器表达示例:
12345678910111213141516171819
>>> gen = (x ** 2 for x in range(5))>>> gen<generator object <genexpr> at 0x7fc2e26b3690>>>> >>> gen.next()0>>> gen.next()1>>> gen.next()4>>> gen.next()9>>> gen.next()16>>> gen.next()Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration>>>
生成器表达式并不能实现较为复杂的功能,所以我们一般都使用生成器函数
生成器函数
在函数中如果出现了yield关键字,那么该函数就不再是普通函数,而是生成器函数
生成器函数可以生成一个无限的序列,列表解析是无法这么做的
yield的作用就是把一个函数变成一个generator,带有yield的函数不再是一个普通函数,Python解释器会将其视为一个
generator。
eg1:简单使用生成器函数 :
12345678910111213141516171819202122232425262728
#!/usr/bin/env python# coding=utf-8def odd(): n = 1 while True: yield n n += 2od = odd()count = 0for i in od: if count > 5: break print i count += 1=========运算结果=======root@tonglele /code/Python/function/test # python code4.py 1357911
在for 循环执行的时候,每次都会执行odd 函数内的代码。
执行到yield n 时,将n 的值返回出去,此时函数内的代码不再往下执行, 挂起状态,但会保存函内变量的相关信息
下次迭代的时,从yield n 的下一条语句,n += 2 开始执行,
这个时候n 的值是之前保留的值,函数体内的while 循环继续执行,当再次执行到yield n 的时候,将n 返回出去,此时的n 是已经计算过n+=2 了
看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。
yeild与return
在一个生成器中,如果没有return,则默认执行到函数结束时返回stopiteration;
12345678910
>>> def gen(): #定义一个生成器... yield 1... >>> g = gen()>>> next(g) #第一次使用next(g)时,会在执行完yield语句后挂起,此时程序并没有执行结束1>>> next(g) #此时,程序从yield语句的下一条语句开始执行,发现已经到了结尾,所以抛出StopIteration异常。Traceback (most recent call last): File "<stdin>", line 1, in <module>StopIteration
如果在执行的过程中遇到了return,则直接抛出StopIteration终止迭代
12345678910111213141516171819202122232425262728293031
>>> def gen():... count = 0... while count < 3:... yield count... count += 1... return... >>> g = gen()>>> next(g) #第一次执行next时,程序停留在执行完yield count之后的位置0>>> next(g) #当这次执行时,先执行count += 1,再向下执行时,遇到了return,所以抛出StopIteration 异常,退出Traceback (most recent call last): File "<stdin>", line 1, in <module>StopIteration>>> def gen():... count = 0... while count < 3:... yield count... count += 1... >>> g = gen()>>> next(g)0>>> next(g)1>>> next(g)2>>> next(g)Traceback (most recent call last): File "<stdin>", line 1, in <module>StopIteration
close()
手动关闭生成器函数,后面的调用会直接返回StopIteration 异常。
1234567891011121314
>>> def gen():... count = 0... while count < 3:... yield count... count += 1... >>> g = gen()>>> next(g)0>>> g.close()>>> next(g)Traceback (most recent call last): File "<stdin>", line 1, in <module>StopIteration
send()
生成器函数最大的特点就是可以接受外部传入的一个变量,并根据变量内容计算结果后返回。这是生成器函数最难理解也是最重要的地方。后面的协程部分会经常用到
123456789101112131415161718192021222324252627282930313233343536
#!/usr/bin/env python#coding=utf-8def gen(): value = 0 while True: receive = yield value if receive == 'e': break value = 'got : %s' % receiveg = gen()print g.send(None)print g.send('hello')print g.send(8989)print g.send('e')print g.send('world')===========运行结果===========root@tonglele /code/Python/function/test # python code6.py0got : hellogot : 8989Traceback (most recent call last): File "code6.py", line 16, in <module> print g.send('e')StopIteration###执行流程:1. 通过g.send(None)或者next(g)可以启动生成器函数,并执行到第一个yield语句结束的位置。此时,执行完了yield语句,但是没有给receive赋值。yieldvalue会输出初始值0注意:在启动生成器函数时只能send(None),如果试图输入其它的值都会得到错误提示信息。2. 通过g.send(‘hello’),会传入hello,并赋值给receive,然后计算出value的值,并回到while头部,执行yield value语句有停止。此时yield value会输出”got:hello”,然后挂起。3. 通过g.send(8989),会重复第2步,最后输出结果为”got: 8989′′4. 当我们g.send(‘e’)时,程序会执行break然后推出循环,最后整个函数执行完毕,所以会得到StopIteration异常。
总结:
1、 按照鸭子模型理论,生成器就是一种迭代器,可以使用for进行迭代。
2、第一次执行next(generator)时,会执行完yield语句后程序进行挂起,所有的参数和状态会进行保存。再一次执行next(generator)时,会从挂起的状态开
始往后执行。在遇到程序的结尾或者遇到StopIteration时,循环结束。
3、 可以通过generator.send(arg)来传入参数,这是协程模型。
4、 next()等价于send(None)
感谢阅读,欢迎指正。
- Python基础-函数[2]
- python基础-内置函数2
- Python基础II---函数基础
- python之函数基础篇2
- python基础语法(7) 函数2
- python基础2之高阶函数
- python基础笔记2-字符串处理函数
- Python运维基础(2)函数
- 【Python基础】函数
- Python基础07 函数
- python基础(3)-函数
- Python基础07 函数
- Python基础07 函数
- Python socket基础函数
- Python基础07 函数
- 【Python】读书笔记,基础函数
- Python<11>函数基础
- Python基础07 函数
- Python基础-基本语法,内置容器
- Java多线程同步
- css3 很实用是特性
- [知识点滴]CSS伪类与伪元素的定义与区别
- Python基础-函数[1]
- Python基础-函数[2]
- React(3)--组件的生命周期
- js关于立即执行函数的一点记录
- response.sendRedirect()和request.getRequestDispatcher().forward(request,response)用法
- Python基础-IO与文本处理
- Spring入门_bean配置与注解实现
- 各种关于ViewGroup中touch事件传递引发的思考
- 【···ところです】前面接动词不同形式
- CursorAdapter和AsyncQueryHandler的简易使用