今日总结04
今天学了函数对象,函数嵌套和闭合函数。函数是自己定义的,平常都是调用函数,也就是函数名加括号表示调用。今天学习了一个新的概念,也就是函数对象,直接来讲就是函数的函数名,注意是不能加括号的。加入自己定义了一个函数def func(x,y,z), func()表示调用函数,也就是执行函数体内的代码,而若不加括号直接就是func表示的是指向的内存空间,也就是将函数名看作是普通的变量。函数对象的使用方法有四个方面,一是可以当作变量进行赋值,即new = func, 调用new()也就是调用func();第二则是可以当成参数进行传值foo(func) ===>func表示的是func的内存地址;第三则是可以当作另一个函数的返回值,return func ===>返回的就是func的内存地址,然后通过内存地址进行调用 ; 第四则是可以当作容器类型的一个元素 ,通过容器取到func的内存地址进行调用,f = ['hh', func,123] ,f[1]==>取到func的内存地址 ,f[1] () 就表示调用func的函数 ;可以使用第四种对(if~else)冗杂的函数进行简化 ,优化代码。
然后是函数嵌套,分为嵌套定义与嵌套 调用,所谓嵌套定义也就是一个函数里面再定义一个函数,被嵌套的函数只能在嵌套函数内进行调用,在全局内不可调用;嵌套调用是在函数内部再调用其他的函数,没有其他别的意义。
然后是闭包函数,所谓闭就是函数内部(父)再定义一个新的函数(子),也就是上面所说的函数嵌套定义,因为只有在嵌套函数(父)内部才能访问到新的子函数,所以称之为闭;”包“ 就是在该函数(子)包含对外层函数作用域名字的引用(不是对全局函数的引用),通俗来讲也就是子中要存在对父内变量名的使用 ,所以闭包函数的总体概念就是名称空间与作用域的运用和函数嵌套。当在父的函数内部返回子的函数对象时就可以在全局空间内调用子函数,当然子函数名字的查找仍然是以函数定义截断为准的。到此就有了两种传参的方式,一种是正常普通的进行形参进行传,另一种也就是通过闭包函数的外部函数(父)传给真正需要参数的内部函数(子)。
接着就是最重点的部分,也就是装饰器。装饰是给为了给其他事物添加额外的东西点缀,器指的是工具,可以定义为新的函数,装饰器则是定义的一个函数,是为了给其他函数添加额外的功能。为了遵循开放封闭原则,开放指对拓展功能开放,封闭则是对修改源代码进行封闭,装饰器则是在不改变源代码的前提下通过添加装饰器来增加其额外的功能。装饰器得出的过程:
原函数:想要加入一段可以记录运行该功能函数所需时间的代码
1 def func(x,y,z): 2 time.sleep(3) 3 print("功能函数%s %s %s"%(x,y,z)) 4 func(1,2,3)
1.直接在函数体内部添加代码 很明显此种方法明显修改了源代码,不符合开放封闭原则
1 import time 2 3 def func(x,y,z): 4 start_time=time.time() 5 time.sleep(3) 6 print("功能函数%s %s %s"%(x,y,z)) 7 end_time=time.time() 8 print(end_time-start_time) 9 func(1,2,3)
2.在函数调用前和后分别加上计算时间的函数,但当调用多次时会使重复代码大大增多,也不能使用
1 import time 2 3 def func(x,y,z): 4 time.sleep(3) 5 print("功能函数%s %s %s"%(x,y,z)) 6 7 8 start_time=time.time() 9 func(1,2,3) 10 end_time = time.time() 11 print(end_time - start_time) 12 13 start_time=time.time() 14 func(1,2,3) 15 end_time = time.time() 16 print(end_time - start_time) 17 18 start_time=time.time() 19 func(1,2,3) 20 end_time = time.time() 21 print(end_time - start_time)
3.为了简化重复代码将其封装成函数进行调用,并且要将其封装成动态的,所以要进行赋值,但还有个问题,当func()里的参数改变时要同时修改wrappe()和函数内fun()里的参数,所以要将后面的两个跟的参数变成可变类型的
1 import time 2 3 def func(x,y,z): 4 time.sleep(3) 5 print("功能函数%s %s %s"%(x,y,z))
return 4 6 7 def wrapper(x,y,z): 8 start_time=time.time() 9 func(x,y,z) 10 end_time = time.time() 11 print(end_time - start_time)
return 4 12 13 wrapper(1,2,3)
4.变成可变类型后也有了问题,相比较原函数可知函数的调用方式不同,且只能装饰同一个功能函数,所以要把func()函数变成可变类型的
1 import time 2 3 def func(x,y,z): 4 time.sleep(3) 5 print("功能函数%s %s %s"%(x,y,z)) 6 7 def wrapper(*args,**kargs): 8 start_time=time.time() 9 func(*args,**kargs) 10 end_time = time.time() 11 print(end_time - start_time)
return 4 12 13 wrapper(1,2,3)
5.变成可变类型就必须使用到闭包函数,还有函数对象的第三种,是另一个函数的返回值,至此装饰器也就写完了
1 import time 2 3 def func(x,y,z): 4 time.sleep(3) 5 print("功能函数%s %s %s"%(x,y,z)) 6 7 def timmer(can_change): 8 def wrapper(*args,**kargs): 9 start_time=time.time() 10 can_change(*args,**kargs) 11 end_time = time.time() 12 print(end_time - start_time)
return 4 13 # 调用timmer返回的是wrapper的内存地址,通过得到的内存地址来调用wrapper 14 return wrapper 15 16 #将得到的wrapper的内存地址赋值给func ,用于偷天换日 17 func = timmer(func) 18 func(1,2,3) #此时调用finc实际是调用wrapper,加上外包只是为了使装饰的函数可以替换
浙公网安备 33010602011771号