python学习笔记之函数总结--高阶函数以及装饰器
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python学习笔记之函数总结--高阶函数以及装饰器相关的知识,希望对你有一定的参考价值。
python学习笔记之函数总结--高阶函数以及装饰器
Python特点:
1、不是纯函数式编程(允许变量存在);
2、支持高阶函数(可以传入函数作为变量);
3、支持闭包(可以返回函数);
4、有限度的支持匿名函数;
高阶函数:
1、变量可以指向函数;
2、函数的参数可以接收变量;
3、一个函数可以接收另一个函数作为参数;
下面我将示例一些函数的写法以及使用,并说明python中函数的特性:
1、基本的高阶函数示例:
#!/usr/bin/env python def func(): print "ext_func" def inn_func(): print "inn_func" return inn_func() print func()
在func函数中我们首先输出的是ext_func表明这是在外部函数中输出的语句,随后在里面定义了内置函数inn_func,在内部函数中输出的是inn_func,最后在外部函数中return返回内部函数的结果
下面是程序运行的结果:
ext_func inn_func None
运行程序,首先调用外部函数func,输出语句ext_func,然后return内部函数,内部函数输出inn_func,函数func调用已经完成,返回结果为inn_func的返回值,其返回值为None,我在最后调用时,是print fun(),即打印func函数的返回值,它返回inn_func的返回值,即为None.
2、我们在上一个程序的基础上,进行改进,在调用时如下:
#!/usr/bin/env python def func(): print "ext_func" def inn_func(): print "inn_func" return inn_func f = func() f()
我们现将func()的返回值传递给变量f,再调用f函数
结果如下:
ext_func inn_func
通过结果,可以看出,第一次是将func()的返回值赋给了f,而func()的返回值就是return inn_func,即把inn_func这个内部函数传递给了变量f,所以在后面调用f()时,就相当于调用函数inn_func(),所以只有两个print 语句输出了。
3、下面是一个对部函数的改进,调用了两个模块time和datetime,简单地实现了一个计时:
#!/usr/bin/env python import time import datetime def func(): print "ext_func" def inn_func(f): start = datetime.datetime.now() f() end = datetime.datetime.now() cost = end - start print cost.total_seconds() return inn_func def f2(): time.sleep(3) f = func() f(f2)
在上面的函数体中,我们对内部函数进行了改进,其中start和end分别是获取当前系统时间,中间是调用了一个函数f,所以end和start的差值就是函数f执行的时间cost,为了显示的是秒,我们对cost做了一个转化为秒数的改动,即调用total_seconds方法。
下面是程序执行后的结果:
ext_func 3.004226
首先将func函数结果传递给变量f的时候,打印了一句ext_func语句,这时函数f其实就是inn_func函数,因为func函数的返回值就是inn_func函数;调用f函数,这时我们要传递一个参数进去,而这个参数还是另一个函数,我们传递的是自定义的f2函数,它sleep了3秒,所以两个查找cost也是3秒,和预期效果一样。
特别要注意的是,调用一个函数的内部函数,有可能是需要传递参数进去了,可能在外部函数传递参数,也可能是在内部函数进行传递参数,一定要注意到底在哪块传递参数,传的参数是什么,在里面哪里调用了,以及在最后使用函数时,如何根据所写的不同,要具体怎样去调用函数。
4、下面在看一个改进后的程序示例:
#!/usr/bin/env python import time import datetime def func(fc): print "ext_func" def inn_func(*arg,**kwargs): start = datetime.datetime.now() fc(*arg,**kwargs) #f2(arg) end = datetime.datetime.now() cost = end - start print cost.total_seconds() return inn_func def f2(arg): print arg time.sleep(arg) def f3(arg1,arg2): print arg1,arg2 time.sleep(5) def f4(): time.sleep(6) f = func(f2) f(4)
在这个程序中,我们传递了参数,首先是对内部函数的参数传递,有时会传递进来一个函数在里面调用,而传递进来的函数有可能也是需要传递参数的,所以我们就要处理传递函数和传递函数参数的问题,一般我们将函数在外部函数中进行传递进来在里面进行调用,而函数所需要的参数,我们可以在内部函数中进行传递,比如上面这个程序,外部函数传递进来的fc在内部函数中进行调用,而传进来函数的参数在内部函数中进行传递;
为了能将所有情况下的参数全部传递进来,所以在内部函数传参时,采用了*arg和**kwargs以保证所有类型的传参都能成功,在具体fc函数调用时,则需要进行解序列传参进去使用,最后的几个函数就是为了进行测试不同参数传参的问题。
下面是程序运行的结果:
ext_func 4 4.005157
可以看到传递了f2函数给外部函数func,将其返回值inn_func传递给f,调用f函数时,还需要传递一个参数进去,这是根据f2函数内部结构得到的,传递的值是4,所以结果和预期一致。
5、下面是一个练习脚本示例:
#!/usr/bin/env python def func1(fc): print "This is a function of boss." print type(fc) def func2(*arg): print "This is a function in function." print arg fc(*arg) print fc(*arg) return func2 def f1(x,y): return x*y f = func1(f1) f(3,5)
结果如下:
This is a function of boss. <type ‘function‘> This is a function in function. (3, 5) 15
6、装饰器的一些示例与作用说明:
#!/usr/bin/env python import time import datetime def func(fc): print "ext_func" def inn_func(*arg): start = datetime.datetime.now() fc(*arg) #f2(arg) end = datetime.datetime.now() cost = end - start print cost.total_seconds() return inn_func @func def f2(arg): print arg time.sleep(arg) @func def f3(arg1,arg2): print arg1,arg2 time.sleep(5) @func def f4(): time.sleep(6) #f = func(f4) #f() #f2(3) #fc = func(f2);fc(3) f3(3,5)
在这段程序中,主要是使用了装饰器,即@func就是下面定义函数的装饰器
在执行的时候直接调用要传递的参数就可以实现和上面一样的功能,这是因为装饰器解释给解释器,自动执行了原来需要手动传递函数的那一步,即fc = func(f2);所以你执行了f2(3),就相当于执行了fc =func(f2); f2(3)两步。
注意:装饰器要在函数定义前进行装饰,每装饰一个函数,解释器都会执行fc = func(f2)这一步,在下面的结果处你就可以看到,每个解释器只能解释一个函数,相同的需要都写在前面。
下面是程序执行的结果:
ext_func ext_func ext_func 3 5 5.005236
可以看到,在程序中值调用了一次函数,就是f3(),可是ext_func打印了三遍,这是因为装饰器的原因,自动执行了一步,但并没有执行后面的内部函数调用,所以只打印ext_func这句话,而f3()则进行了调用,且传递了参数为5,所以打印结果是时间。和预期效果一致。
7、练习示例:
#!/usr/bin/env python def check_priv(fc): defwrap(*arg,**kwargs): ifusername == ‘admin‘: fc(*arg,**kwargs) else: print"Permission denied" returnwrap username = "admin" @check_priv def f6(arg): printarg print"restart nginx...",arg f6(‘ok‘)
结果如下:
ok restart nginx... ok
8、装饰器结合functools返回函数自身属性(函数名):
#!/usr/bin/env python import functools def func_boss(func): print "This is a function boss" @functools.wraps(func) def func_son(*arg,**kwargs): print "This is a functionson" func(*arg) print "Ending" return func_son S = 1 @func_boss #func_test = func_boss(func_test) def func_test(*arg): print "This is a function test" #S = 1 global S for i in range(len(arg)): S = S*arg[i] print S return S #func_test(1,2,3,4) #func_test() a = func_test print a.__name__
在上面的程序中,我们看到func_boss作为装饰器装饰了函数func_test,这样等于是执行了func_test =func_boss(func_test)这一步,这我们都在上面进行了说明;
那么如果我调用函数func_test时,如果要获取它的名字,返回的结果是什么呢,通过测试发现它返回的是内部函数func_son,这并不是我们想要的结果,因为执行了装饰器的功能,所以函数的属性已经变成了内部函数func_son的,因为func_test就是接受了装饰器的结果,即return func_son。
这时,如果我们想要原来函数的属性的话,可以借助functools模块,首先应该导入这个模块,在装饰器函数里面进行调用,这里是在内部函数func_son定义之前加一个解释器@functools.wraps(func),它的功能是将func函数的属性赋给高阶函数中的内部函数(又称为wrap函数),这样执行的结果就是我们想要的。
不加@functools.wraps(func)的结果如下所示:
This is a function boss func_son
加@functools.wraps(func)的结果如下:
This is a function boss func_test
和我们想要的结果一样,获取到的是func_test函数名
9、yield的用法及示例(一):
!/usr/bin/env python def odd(): n= 1 print"hello yield" whileTrue: #print"before yield" yieldn print"after yield" n+=2 for i in odd(): printi ifi >= 101: break
yield出现的函数就会有一个迭代器,它返回的值是依次取的,当你需要用的时候才会给你,不会马上把所有的值都取完,这样太费内存,浪费资源,yield就是返回一个值就会停住,进行等待,当你下一次需要值时,它才执行去返回下一个值,否则就一直停在那,这样做的好处是节省资源。
o = odd() print "=======" print o.next() print o.next() print o.next() print o.next()
获取yield的返回值(迭代器的返回值)可以使用.next()方法进行获取,获取完所有值就不再有值了,每获取一个值迭代器指向的位置就会变化一次,直到取完所有值。
10、yield用法及示例(二):
#!/usr/bin/env python def gen(): value= 0 whileTrue: recv= yield value ifrecv == ‘e‘: break value= "gen:%s" % recv g = gen() print g.send(None) #g.next() print g.send(‘aaaa‘) print g.send(‘bbbb‘) print g.send(‘cccc‘) print g.send(‘dddd‘)
在上面的程序中,我们主要是要介绍send()方法,是怎样使用的,在函数定义中,我们看recv = yield value这一句,这一句是可以给yield传进来值的,即yield是可以接受send过来的值。
由于yield的特殊性,它在返回一个值的时候就已经停下来了,所以第一次并没有接受send的值,下面调用时的第一个g.send(None),相当于是g.next(),这就是让yield在往下进行一次取值,跳过第一次返回值后就停止的状态,接下来就是一次接受send的值,然后进行替换value值后返回,为了测试可在前后加一些必要的测试语句查看有什么不同,帮助理解。
下面是程序执行的结果:
0 gen:aaaa gen:bbbb gen:cccc gen:dddd
11、下面是改进以后的示例,加入了一些别的功能,可以帮助理解yield和send方法的使用:
#!/usr/bin/env python def sgen(): value= 0 whileTrue: rec= yield value ifrec == "quit": value= ‘please input "q" to quit‘ elifrec == "hello": #print"hello,nihao" value= "hello,@you" else: value= "what are you say?" s = sgen() s.send(None) #跳出第一次停等状态 while True: TEXT= raw_input("please input:") ifTEXT == "q": break prints.send(TEXT)
结果如下:
please input:ok what are you say? please input:hello hello,@you please input:quit please input "q" to quit please input:q
本文出自 “ptallrights” 博客,请务必保留此出处http://ptallrights.blog.51cto.com/11151122/1791393
以上是关于python学习笔记之函数总结--高阶函数以及装饰器的主要内容,如果未能解决你的问题,请参考以下文章