二、装饰器
所谓装饰器decorator仅仅是一种语法糖, 可作用的对象可以是函数也可以是类, 装饰器本身是一个函数, 其主要工作方式就是将被装饰的类或者函数当作参数传递给装饰器函数。本质上,装饰器就是一个返回函数的高阶函数
假设有这么一个应用场景,一个公司的监控监控系统有很多函数用来监控不同的数据,突然有一天老大要把这么多函数,需要一个日志功能,也就是在执行函数前和执行函数后再控制台和文件中输出日志。
如果老大把这个任务交个你,你会怎么做?把每个函数都修改一遍吗?如果老大觉得日志功能太影响性能,又要去掉,怎么办?一个又一个的改回来??如果函数少需要修改的地方少还可以,如果需要修改的地方很多的话,这样显然是不明智的。用装饰器就可以很好的解决这个问题。我们先来看一下装饰器如何定义。
1、定义装饰
1 def log(func): 2 def wrapper(*args, **kwargs): 3 print('call %s():' % func.__name__) 4 return func(*args, **kwargs) 5 return wrapper
说明:看上去和定义一个函数没多大区别,只不过在函数里有嵌套了一层函数而已。1)log为装饰器名称,可以随意定义,就像普通函数。2)装饰器的参数func为一个函数,表示要装饰的函数。3)装饰器里面的函数名可以随意,参数的话可以根据被装饰的函数的情况而定,参数的作用只是为了把参数有重新传回被装饰的函数。通常使用*args, **kwargs为了可以匹配各种函数的参数个数等
2、装饰器的调用
调用装饰器来装饰函数,我们只需要使用Python的语法糖,在被装饰函数上方使用@装饰名的方式调用,比如我们要调用上面的log装饰器
1 @log 2 def Foo(): 3 print('Foo') 4 Foo() 5 执行结果 6 call Foo(): 7 8 Foo
3、装饰器原理
其实装饰器的调用@装饰器名是一个语法糖,Python解释器在解释到这里的时候为我们做了如下工作
1 Foo = log(Foo)
说明:
1)调用装饰器函数将被装饰的函数作为参数传递过去。
2)这样就相当于重构了这个函数,也就是包裹了一层内容。
3)装饰器本身一个可以接收参数,但是,由于使用场合比较少,甚少会用到,这里就不讲解了,其实原理就是在定义装饰器的时候在外面再裹上一层函数
三、递归
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。
递归算法解决问题的特点:
(1) 递归就是在过程或函数里调用自身。
(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
(3) 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。
(4) 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。所以一般不提倡用递归算法设计程序。
递归算法所体现的“重复”一般有三个要求:
(1) 每次调用在规模上都有所缩小(通常是减半);
(2) 相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入);
(3) 在问题的规模极小时必须用直接给出解答而不再进行递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束。
实例,通过递归实现二分查找
1 def binary_search(data_list,find_num): 2 mid_pos = int(len(data_list) /2 ) # 获取中间的索引 3 mid_val = data_list[mid_pos] # 获取中间的索引对相应元素,也就是值 4 print(data_list) 5 if len(data_list) >1: # 递归结束条件,也就是规模绩效 6 if mid_val > find_num: # 中间的值比要找的值大,说明在中间值左边 7 print("[%s] should be in left of [%s]" %(find_num,mid_val)) 8 binary_search(data_list[:mid_pos],find_num) # 递归自己,继续查找自己的左边(也就是递归要求里的缩小调用规模) 9 elif mid_val < find_num: # 中间的值比要找的值大,说明在中间值左边 10 print("[%s] should be in right of [%s]" %(find_num,mid_val)) 11 binary_search(data_list[mid_pos + 1:],find_num) 12 else: # 如果既不大于也不小于说明正好等于 13 print("Find ", find_num) 14 15 else: 16 # 当列表的大小等于1的时候,不在调用自己,结束递归 17 if mid_val == find_num: # 判断最用一个元素是否等于要查找的数 18 print("Find ", find_num) 19 else: 20 print("cannot find [%s] in data_list" %find_num) 21 22 if __name__ == '__main__': 23 primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103,104] 24 binary_search(primes,5) 25 binary_search(primes,66)
执行结果
1 [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 104] 2 [5] should be in left of [47] 3 [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43] 4 [5] should be in left of [19] 5 [2, 3, 5, 7, 11, 13, 17] 6 [5] should be in left of [7] 7 [2, 3, 5] 8 [5] should be in right of [3] 9 [5] 10 Find 5 11 [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 104] 12 [66] should be in right of [47] 13 [53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 104] 14 [66] should be in left of [79] 15 [53, 59, 61, 67, 71, 73] 16 [66] should be in left of [67] 17 [53, 59, 61] 18 [66] should be in right of [59] 19 [61] 20 cannot find [66] in data_list