1、函数即变量,调用f() ,也可以写a = f,a() = f()
函数也可以作为参数,也可以作为返回值
2、高阶函数
以函数作为参数,或者返回值是参数的函数
3、函数嵌套
函数里面定义函数
装饰器 = 高阶函数+嵌套函数
1、python装饰器~高阶函数
1 import time 2 def bar(): 3 time.sleep(3) 4 print('in the bar') 5 def test1(func): 6 print(func) #打印这个func的内存地址 7 return func #把函数的返回值返回 8 #test1(bar) #把bar传给func 相当于func = bar,把上面的bar函数传进来 9 print(test1(bar)) #打印一下才能看到它的返回值 调用test1函数,bar这个函数传进来了,bar传给func了, 然后func函数里打印(func) 就出来第一个内存地址 完了结束后retuan返回,相当于返回了test1(bar)的运行结果 10 test1(bar)#output bar的内存地址
进一步说明调用规则
1 import time 2 def bar(): 3 time.sleep(3) 4 print('in the bar') 5 def test1(func): 6 print(func) #打印这个func的内存地址 7 return func #把函数的返回值返回 8 t =(test1(bar)) 9 #print (t) #test1(bar)传进来,立马打印bar的函数地址,又return就把bar内存地址返回回来给t,又把t输出出来 10 #t() #run bar 11 bar = test1((bar)) #把之前的bar覆盖掉 这个换个写法 12 bar() #run bar
2、python嵌套函数
3、装饰器案例详解
1 import time 2 def deco(func): 3 start_time=time.time() 4 func() #相当于执行一次func函数,意思是执行test1和test2函数,然后打印相应函数里print出来的数值 5 stop_time=time.time() 6 print("the func run time is %s"%(start_time-stop_time)) 7 def test1(): 8 time.sleep(3) 9 print('in the test1') 10 def test2(): 11 time.sleep(3) 12 print('in the test2') 13 deco(test1) #如果加括号是把test1运行结果和返回值传递给deco函数, 14 deco(test2)
统计两个函数中间花费的时间
改进; 引入@ 好难懂
1 import time 2 def timer(func): #timer(test1 ) 内存地址传给,test1没加括号,所以是内存地址 3 def deco(): 4 start_time=time.time() 5 func() #这样就直接返回内存地址 但,return后的不会继续运行 6 stop_time =time.time() 7 print("the func run time is %s"%(start_time - stop_time)) 8 return deco #返回函数的内存地址 所以把这个内存地址打印出来 9 @timer # 相当于 test1 = timer(test1) 10 def test1(): 11 time.sleep(3) 12 print('in the test1') 13 test1() #执行这个实际是执行deco
有一些函数,如test1不需要 arg参数,而test2就需要args(不输入args 会报错)
1 import time 2 def timer(func): #timer(test1 ) 内存地址传给,test1没加括号,所以是内存地址 3 def deco(arg1): 4 start_time=time.time() 5 func(arg1) #这样就直接返回内存地址 但,return后的不会继续运行 6 stop_time =time.time() 7 print("the func run time is %s"%(start_time - stop_time)) 8 return deco #返回函数的内存地址 所以把这个内存地址打印出来 9 #@timer # 相当于 test1 = timer(test1) 10 def test1(): 11 time.sleep(3) 12 print('in the test1') 13 14 @timer # = test2 = timer(test2) = deco test2() = deco() 15 def test2(name): 16 print("test2:",name) 17 18 #test1() #执行这个实际是执行deco 19 test2("li")
引用
1 import time 2 def timer(func): #timer(test1 ) 内存地址传给,test1没加括号,所以是内存地址 3 def deco(*args,**kwargs): #所以就引用了非固定参数 4 start_time=time.time() 5 func(*args,**kwargs) #这样就直接返回内存地址 但,return后的不会继续运行 6 stop_time =time.time() 7 print("the func run time is %s"%(start_time - stop_time)) 8 return deco #返回函数的内存地址 所以把这个内存地址打印出来 9 #@timer # 相当于 test1 = timer(test1) 10 def test1(): 11 time.sleep(3) 12 print('in the test1') 13 14 @timer # = test2 = timer(test2) = deco test2() = deco() 15 def test2(name): 16 print("test2:",name) 17 18 test1() #执行这个实际是执行deco 19 test2("li")
装饰器小调用
1 import time 2 def timer(func):#5 3 def deco(): 4 start = time.time() 5 func() 6 stop = time.time() 7 print(stop-start) 8 return deco #这样会返回一个deco函数,但不会执行,因为没调用 9 def test(): 10 time.sleep(2) 11 print("test is running!") 12 test = timer(test) #6 13 test() #7
首先,在#6处,把test作为参数传递给了timer(),此时,在timer()内部,func = test,接下来,定义了一个deco()函数,但并未调用,只是在内存中保存了,并且标签为deco。在timer()函数的最后返回deco()的地址deco。
然后再把deco赋值给了test,那么此时test已经不是原来的test了,也就是test原来的那些函数体的标签换掉了,换成了deco。那么在#7处调用的实际上是deco()。
那么这段代码在本质上是修改了调用函数,但在表面上并未修改调用方式,而且实现了附加功能。
意思就是不能改变调用方式,就把调用的函数体标签换掉,让test() = timer(test)
这样做的原因是:
我们要保留test(),还要统计时间,而test()只能调用一次(调用两次运行结果会改变,不满足),再根据函数即“变量”,那么就可以通过函数的方式来回闭包。于是乎,就想到了,把test传递到某个函数,而这个函数内恰巧内嵌了一个内函数,再根据内嵌函数的作用域(可以访问同级及以上,内嵌函数可以访问外部参数),把test包在这个内函数当中,一起返回,最后调用这个返回的函数。而test传递进入之后,再被包裹出来,显然test函数没有弄丢(在包裹里),那么外面剩下的这个test标签正好可以替代这个包裹(内含test())。
4、真正的装饰器
Python提供了一种语法糖,即用@timer 来代替 test= timer(test)
这两句是等价的,只要在函数前加上这句,就可以实现装饰作用。
5、装饰有参函数
对于一个实际问题,往往是有参数的,如果要在#8处,给被修饰函数加上参数,显然这段程序会报错的。错误原因是test()在调用的时候缺少了一个位置参数的。而我们知道test = func = deco,因此test()=func()=deco()
,那么当test(parameter)有参数时,就必须给func()和deco()也加上参数,为了使程序更加有扩展性,因此在装饰器中的deco()和func(),加如了可变参数*agrs和 **kwargs。
improt time def timer(func) def deco(*args, **kwargs): #加上被修饰函数的参数才会被调用 start = time.time() func(*args, **kwargs) stop = time.time() print(stop-start) return deco @timer def test(parameter): #8 time.sleep(2) print("test is running!") test()
6