一、递归
- 定义:本质上是回溯和递推
- 回溯:询问答案的过程
- 递推:推出答案的过程
- 前提:
- 回溯到一个有结果的值开始递推
- 回溯与递推的条件要有规律
- 方式:
- 直接递归:自己调用自己
- 间接递归:通过别人来调用自己
- 栈溢出问题:
- 递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
- 使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。
-
RuntimeError: maximum recursion depth exceeded in comparison 栈溢出报错
-
解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。
尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
- 总结:
-
使用递归函数的优点是逻辑简单清晰,缺点是过深的调用会导致栈溢出。
-
针对尾递归优化的语言可以通过尾递归防止栈溢出。尾递归事实上和循环是等价的,没有循环语句的编程语言只能通过尾递归实现循环。
-
Python标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题
-
# -*- coding: utf-8 -*- # 完成阶乘计算 n! = 1*2*3.....*(n-1)*n=n*(n-1)! def fact(n): if n==1: return 1 return fact(n-1)*n print(fact(5)) # 斐波那契 def fib(a, b, stop): if a > stop: return print(a, end=' ') fib(b, a + b, stop) fib(0, 1, 10) # 0 1 1 2 3 5 8
# 什么是递归,完成询问年龄的递归,第一个⼈年纪10岁,后一个⼈是前一个⼈年纪的3倍,依次类推,求第三个⼈年纪 def fn(n): age = 10 if n == 1: return age age = fn(n - 1) * 3 return age print(fn(3)) # 90 def fn(n, age): if n == 1: return age age = fn(n - 1, age) * 3 return age print(fn(3, 10)) # 90
二、匿名函数(lambda):当我们在传入函数时,有时候不需要显式的定义函数,直接传入匿名函数更为方便
- 语法:lambda 参数:表达式
关键字 lambda 表示 匿名函数, 冒号(:)前的x表示函数参数,匿名函数有个限制,就是只有一个表达式,不用写return,返回值就是该表达式结果。
匿名函数优点:没有名字,因此不必担心名字冲突问题,另外,匿名函数也是个函数对象,也可以把匿名函数赋值给一个变量,在利用变量来调用函数(一般不这么操作,这样会失
去匿名函数本身的意义),也可以把匿名函数作为函数返回值使用。
# 匿名函数本质就是一个没有函数名没有函数体只有一个返回值(可以还返回一个值,或是列表字典等)的函数语法糖形式 # 一般结合内置函数使用,作为回调函数来使用 # 关键字:lambda |参数列表省略() # 定义语法: # lambda 参数列表:一个返回值表达式 f = lambda x, y: x + y # 如果用变量接受,则相当于有名函数,一次一般不这么用 # 应用场景:(一般不用一个变量名去接受) # 1.匿名函数函数地址可以被一个变量接受,该函数可以作为函数名来使用,但违背初中 # 2.结合内置函数使用 : 内置函数某些参数需要一个函数地址 # 可以赋值一个有名函数名,也可以直接赋值匿名函数 def fn(arg): print(arg) return arg ls = [100, 200, 30, 40] res = max(ls) res2 = max(ls, key=fn) print('_____________________________________________') print(res) print('****************************************************') res1 = max(ls, key=lambda ele: ele) print(res1)
三 、内置函数
# 内置函数 iterable = [1, 2, 3, 4, 5, 65, 4] res = max(iterable, key=lambda x: x) # 参数:可迭代对象遍历的元素,但绘制:作比较的值 print(res) iterable = { 'Bob': 12000, 'Tom': 37000, 'Jerry': 7600, 'Zero': 1200, } res = max(iterable, key=lambda x: x) print(res) res = max(iterable, key=lambda x: iterable[x]) print(res) print('&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&') iterable = { 'Bob': {'no': 120, 'money': 120500}, 'Tom': {'no': 130, 'money': 120040}, 'Jerry': {'no': 10, 'money': 1200230}, 'Zero': {'no': 1120, 'money': 120100} } res = max(iterable, key=lambda k: iterable[k]['no']) print(res) res = max(iterable, key=lambda x: iterable[x]['money']) print(res) print('&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&') iterable = { 'Bob': [121, 120500], 'Tom': [20, 1205120], 'Jerry': [10, 120510], 'Zero': [120, 1220500], } # sorted 方法排序 res = sorted(iterable, key=lambda x: iterable[x][0]) # 按员工号排序 print(res) res = sorted(iterable, key=lambda x: iterable[x][1]) # 按员工号排序 print(res) # map :映射 res = map(lambda x: x + 10, [1200, 3600, 4000, 2300]) print(list(res)) # reduce: 合并 from functools import reduce res = reduce(lambda f, n: f * n, [1, 2, 3, 4, 5]) # 阶乘5! print(res) # 120 ''' # 重点: # 反射 # getattr() # setattr() # delattr() # classmethod() # staticmethod() # super() # 名称空间《==》可执行字符串 # exec() # enumerate() # isinstance() # len() # max() # min() # object() # open() # range() # abs() 求绝对值 ''' print(abs(-10)) # 10 # all() 全真才真,可迭代元素所有元素全我真才真 print(all([1, 2, 3])) # True print(all([1, 2, None])) # False print(all([1, '', None])) # False print(any([0, 1, None])) # True any元素有真则真 # bin()求二进制 oct()8进制 # eval(可以理解为将字符串去除 ,形成可执行对象