继续来讲一下函数吧,装饰器还分为多层装饰器和有参装饰器,这些知识基本用的不多,了解即可,递归函数和简单算法之二分法也是了解先。
多层装饰器就是给同一个函数使用了三个装饰器来装饰,然后使用三个语法糖从上而下进行装饰,先从最靠近被装饰对象的语法糖说起,这个语法糖把该装饰器的内部函数给返回出来了,然后拿这个内部函数去传给第二个语法糖,第二个语法糖传入了第三个装饰器的内部函数,然后返回了自己的内部函数,然后第二个装饰器的内部函数传给了第一个装饰器,装饰器返回了自己的内部函数并且赋值给了和被装饰对象相同的变量名。
def outter1(func1): print('加载了outter1') def wrapper1(*args, **kwargs): print('执行了wrapper1') res1 = func1(*args, **kwargs) return res1 return wrapper1 def outter2(func2): print('加载了outter2') def wrapper2(*args, **kwargs): print('执行了wrapper2') res2 = func2(*args, **kwargs) return res2 return wrapper2 def outter3(func3): print('加载了outter3') def wrapper3(*args, **kwargs): print('执行了wrapper3') res3 = func3(*args, **kwargs) return res3 return wrapper3 @outter1 @outter2 @outter3 def index(): print('from index') ''' 结果为 加载了outter3 加载了outter2 加载了outter1 执行了wrapper1 执行了wrapper2 执行了wrapper3 from index '''
有参装饰器主要作用是给装饰器传额外参数用的就是在装饰器外部又套了一个函数来传递额外参数。如果要根据传入类型来区别不同的处理过程要用分支结构,且判断条件的参数要靠额外参数的传参。
def outer(source_data): def login_auth(func_name): # 不能动 只能接收一个被装饰对象名字 def inner(*args, **kwargs): # 不能动 是专门用来给被装饰的对象传参的 username = input('username>>>:').strip() password = input('password>>>:').strip() # 校验用户数据 数据的来源可以有很多 比如全局字典 全局列表 文本文件 数据库 # 数据的来源不同 处理方式就不同 对应的代码编写就不一样 # 分支结构处理 然后根据不同的参数提示 匹配不同的流程 if source_data == '1': print('使用字典的方式处理数据') elif source_data == '2': print('使用列表的方式处理数据') elif source_data == '3': print('使用文件操作处理数据') else: print('其他操作情况') res = func_name(*args, **kwargs) return res return inner return login_auth # 函数名加括号,执行优先级最高 @outer('3') # 先看函数和括号内,这里返回了login_auth函数名,然后再考虑语法糖 def index(): print('from index')
递归函数也成为函数的递归,主要就是函数在运行的过程中直接或间接调用了它自身。递归函数有最大递归深度,超出限制python解释器就会启动应急机制,强制报错。python解释器的最大递归深度是可以自己设置的,官方默认为1000,sys.getrecursionlimit()可以用来设置。其它一些编程语言没有应急机制,只有当计算机崩溃才停止。函数的递归不应该是无止境的,函数的递归要满足两个条件。第一个就是每次递归,复杂程度降低(就是下一次递归要比上一次递归更加接近答案)。第二个就是要有明确的结束条件。
def get_age(n): if n == 1: # 明确结束条件 return 18 # 有明确的结束条件 return get_age(n-1) + 2 # get_age(n-1) 每一次更加接近答案
二分法其实就是对有序数列每次取中间值,对于从下到大的顺序序列来说,如果中间值大于要查询的值那么就取左边半段的中间值,如果大于要查询的值那么就去右边半段的中间值。以此类推,可以用到递归。没有最完美的算法,二分法的缺点就是只能对有序序列使用,且如果要查找的数据在最边上,那么效率低。
l1 = [13,21,35,46,52,67,76,87,99,123,213,321,432,564,612] def get_target(l1,target_num): # 最后需要考虑找不到的情况 l1不可能无限制二分 if len(l1) == 0: print('不好意思 真的没有 找不到') return # 1.获取中间元素的索引值(只能是整数) middle_index = len(l1) // 2 # 2.判断中间索引对应的数据与目标数据的大小 if target_num > l1[middle_index]: # 3.保留数据集右侧 l1_left = l1[middle_index+1:] # 3.1.对右侧继续二分 重复执行相同代码 并且复杂度降低 print(l1_left) get_target(l1_left,target_num) elif target_num < l1[middle_index]: # 4.保留数据集左侧 l1_right = l1[:middle_index] print(l1_right) # 4.1.对右侧继续二分 重复执行相同代码 并且复杂度降低 get_target(l1_right,target_num) else: print('找到了',target_num) # get_target(l1,432) # get_target(l1,22) get_target(l1,13)