一、函数递归
1.什么是递归
函数在调用阶段直接或者间接的又调用了自身
(1)直接
def func(): print('from func') func() func()
死循环,无限调用函数
(2)间接
def index(): print('from index') login() def login(): print('from login') index() index()
也是死循环,无限调用这两个函数,不是在自身函数中直接调用,而是间接调用
2.递归深度
Python为了避免函数无限递归下去,设置了一个函数递归深度(重复执行上限),避免函数无限递归,导致计算机内存空间溢出(发生卡死,死机)。
(1)如何查看递归深度
import sys # 调用模块 print(sys.getrecursionlimit()) # 查看递归深度
递归深度(重复调用)默认是1000,不过不是很准确
def func(n): print('from func',n) func(n+1) func(1) # 精确一点的python中最大递归深度是998左右
精确一点的python中最大递归深度是998左右
(2)如何修改最大递归深度
import sys # 调用模块 sys.setrecursionlimit(2000) # 修改递归深度 def func(n): print('from func',n) func(n+1) func(1)
结论:函数不应该无限制的递归下去
3.递归用在什么地方
如果让函数无限制的递归下去没有任何意义,那递归应该用在什么场景?
举个例子:
询问A的年龄,A说比B小两岁,又问B,B说比C小两岁,再问C,C说比D小两岁......,直到E说他26岁,一个个推导得出A18岁
递归分为两个阶段:
(1)回溯:就是一次次重复询问的过程,这个重复的过程必须建立在每一次重复问题的复杂度都应该下降,直到有一个最终的结束条件(就是E说出26岁)
(2)递推:一次次往回推导的过程(推导出A18岁)
用代码演示这个例子:
''' age(A) = 18 age(B) = age(A) + 2 age(C) = age(B) + 2 age(D) = age(C) + 2 age(E) = age(D) + 2 age(1) = 18 age(2) = age(1)+2 age(n) = age(n-1)+2 # n>1 ''' def age(n): if n == 1: # 必须要有结束条件 return 18 # 返回18岁 else: return age(n-1) + 2 res = age(5) print(res)
如何做到:
将列表中的数字依次打印出来:l = [1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,[13,]]]]]]]]]]]]]
推导思路:
l = [1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,[13,]]]]]]]]]]]]] for i in l: if type(i) is int: print(i) else: for item in i: if type(item) is int: print(item) else: for j in item: if type(item) is int: print(item) else: ... # 无限重复,前提还得知道有多少层列表
如果不知道多少层列表怎样做
l = [1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,[13,]]]]]]]]]]]]] def get_num(l): for i in l: if type(i) is int: # 如果是整型就打印 print(i) else: # 否则再循环这个列表 get_num(i) get_num(l)
结论:递归函数不需要考虑循环的次数,只需要把握结束的条件即可
二、算法之二分法
1.什么是算法
解决问题的高效率的方法
2.如何实现:
找到num=345是不是在 l = [1,3,5,12,57,89,101,123,146,167,179,189,345]列表中
l = [1,3,5,12,57,89,101,123,146,167,179,189,345] num = 345 for i in l: if num == i: print('找到了')
如果这个列表有非常多数据,那查找效率就会变低,算法就是提高效率的方法,比如这里可以用二分法
3.二分法
先在列表中间找,然后判断出在哪一边,然后在那一边的中间再找,没找到就再重复上述操作,提高查找效率
l = [1,3,5,12,57,89,101,123,146,167,179,189,345] def get_num(l,target_num): print(l) # 把每次切取到的列表打印下 if not l: # 判断列表是否为空了,空了还没找到就说明不在列表中 print('你要找的值不在列表中') return middle_index = len(l) // 2 # 获取列表中间的索引 if target_num > l[middle_index]: # 判断target_num跟middle_index对应的数字的大小 num_right = l[middle_index + 1:] # 切取列表右半部分 get_num(num_right,target_num) # 再递归调用get_num函数,传入的列表变成切取的新列表 elif target_num < l[middle_index]: # 判断target_num跟middle_index对应的数字的大小 num_left = l[0:middle_index] # 切取列表左半部分 get_num(num_left, target_num) # 再递归调用get_num函数,传入的列表变成切取的新列表 else: # target_num = l[middle_index]的情况 print('找到了') get_num(l,345) get_num(l,666)
使用二分法有一个前提:
容器类型里面的数字必须有大小顺序,没有顺序可以使用 sort() 进行排序
三、三元表达式
1.比较大小的函数
def my_max(x,y): if x > y: return x else: return y print(my_max(1,5))
当x大的时候返回x,当y大的时候返回y,也就是当某个条件成立做一件事,不成立做另外一件事
2.如何用三元表达式表示这个函数
x = 1 y = 5 res = x if x > y else y # 如果if后面的条件成立返回if前面的值,否则返回else后面的值 print(res)
如果if后面的条件成立返回if前面的值,否则返回else后面的值
3.三元表达式的固定语法结构
值1 if 条件 else 值2
条件成立返回值1
条件不成立返回值2
4.三元表达式的应用场景
三元表达式只推荐只有两种情况的可能下
例如:
is_free = input('请输入是否免费(y/n)>>>:') is_free = '免费' if is_free == 'y' else '收费' print(is_free)
username = input('username>>>:') res = 'NB' if username == 'francis' else '垃圾' print(res)
四、列表生成式
1.如何实现:
使列表中的字符串后面加上字符 _NB:l = ['tank','nick','oscar','sean']
l = ['francis','jason','tank','egon'] l1 = [] for name in l: l1.append('%s_NB'%name) # l1.append(name + '_NB') # 等价于上面的办法,不推荐使用,python中这种字符串拼接效率太低 print(l1)
如何简单实现,需要用到列表生成式
2.列表生成式
l = ['francis','jason','tank','egon'] res = ['%s_NB'%name for name in l] # for循环依次拿出name交给for前面的,作为列表的一个个元素 print(res)
原理:for循环依次拿出name交给for前面的,作为列表的一个个元素
3.列表生成式还可以加上if判断
取出列表中以 _NB结尾的元素:l = ['francis_NB','jason_NB','tank_NB','egon']
l = ['francis_NB','jason_NB','tank_NB','egon'] res = [name for name in l if name.endswith('_NB')] # 后面不支持再加else的情况 # 先for循环依次取出列表里面的每一个元素 # 然后交由if判断,条件成立才会交给for前面的,作为列表的一个个元素 # 如果条件不成立,当前的元素,直接舍弃 print(res)
原理:先for循环依次取出列表里面的每一个元素,然后交由if判断,条件成立才会交给for前面的,作为列表的一个个元素,如果条件不成立,当前的元素,直接舍弃
五、字典生成式
1.如何实现:
把两个列表的数值一一对应,组成一新个字典:l1 = ['name','password','hobby']、l2 = ['francis','123','read']
l1 = ['name','password','hobby'] l2 = ['francis','123','read'] d = {} for k,v in enumerate(l1): # v是新字典的key,k是l2值对应的索引 d[v] = l2[k] print(d)
2.字典生成式
l = ['francis','123','read'] d = {i:j for i,j in enumerate(l) if j != '123'} # 还可以加上if判断,如果j不等于'123'就交个for前面的,否则舍弃 print(d)
3.集合生成式
s = {i for i in range(10) if i != 4} print(s)
只要记住这个格式,外面加什么就生成什么(基本)
4.生成器表达式
t = (i for i in range(10) if i != 4) # 这样写不是元组生成式,而是生成器表达式 print(t) # 返回的是个老母猪 for i in t: print(i)
六、匿名函数
1.什么是匿名函数
没有名字的函数(也就意味着之后无法通过函数名加括号调用),所以是临时存在的函数,用的时候才存在,用过就没了
2.怎么用
lambda x,y:x+y # 求和的匿名函数 就等价于下面的有名函数 def my_sum(x,y): return x + y # 求和的有名函数
lambda x,y:x+y
(1)冒号(:)左边的相当于函数的形参
(2)冒号(:)右边的相当于函数的返回值
(3)匿名函数通常不会单独使用,而是配合内置函数一起使用
(4)也可以加括号使用,不过用完就没了
res = (lambda x,y:x+y)(1,2) # 加括号使用并传参数 print(res)
(5)也可以给匿名函数命名,命名知乎就变成有名函数了,但失去了匿名函数的意义
func = lambda x,y:x+y print(func(1,2)) # 函数加括号调用
七、常用的内置函数
1.max、min(最大值,最小值)
得出薪资最高的人的名字(比较薪资,返回人名):
d = {'francis':30000, 'jason':20000, 'egon':15000, 'tank':10000}
(1)直接用max比较
d = {'francis':30000, 'jason':20000, 'egon':15000, 'tank':10000} print(max(d)) # 比较的是字典的key的大小,得出tank,不对
比较的是字典的key的大小(字典暴露给用户的只有key)
(2)调用函数的办法
d = {'francis':30000, 'jason':20000, 'egon':15000, 'tank':10000} def index(name): return d[name] print(max(d,key=index)) # max支持传一个函数,这样传入的key就被函数index变成了value,比较的就是value了
这样index函数只是为下面的比较大小服务的,就可以简化成匿名函数
d = {'francis':30000, 'jason':20000, 'egon':15000, 'tank':10000} print(max(d,key=lambda name:d[name])) # 冒号左边是函数的形参,右边是返回值
得出薪资最低的人也是这样
d = {'francis':30000, 'jason':20000, 'egon':15000, 'tank':10000} print(min(d,key=lambda name:d[name]))
2.map(映射)
把列表中的每个数字都加1:l = [1,2,3,4,5,6]
l = [1,2,3,4,5,6] res = map(lambda a:a+1,l) # map是基于for循环的,返回的是一个老母猪 print(list(res)) # list会循环老母猪里的数值组成列表
3.zip(拉链)
让列表中的值一一组合在一起:l1 = [1,2,3]、l2 = ['jason','egon','tank']、l3 = ['a','b','c']
l1 = [1,2,3,4] l2 = ['jason','egon','tank'] l3 = ['a','b','c'] print(list(zip(l1,l2,l3))) # 得出的是列表中包含一对对元组 # 如果某列表元素多于其他列表也不影响,只保留能对应上的部分
4.filter(过滤)
返回一个新列表,去除3:l = [1,2,3,4,5,6]
l = [1,2,3,4,5,6] res = filter(lambda x:x != 3,l) # filter是基于for循环的,返回的是一个老母猪 print(list(res)) # list会循环老母猪里的数值组成列表
5.sorted(排序)
给列表排序:l = [3,5,1,4,2,4]
l = [3,5,1,6,2,4] res = sorted(l) # 相当于sort,默认升序 print(res) res1 = sorted(l,reverse=True) # 也可以传参数,变为降序 print(res1)
6.reduce
类似于一个工厂,你给我多份材料,我只返回一个结果(给我一个列表,只返回一个值)
把列表中的值相加:l = [1,2,3,4,5,6]
(1)没有初始值的时候
l = [1,2,3,4,5,6] from functools import reduce # reduce不可以直接用,需要先导入一个模块 print(reduce(lambda x,y:x+y,l)) # 没有初始值 # 没有初始值的时候,第一次获取两个值然后相加,之后每次获取一个值与上一次相加的结果再相加
(2)有初始值的时候
l = [1,2,3,4,5,6] from functools import reduce # reduce不可以直接用,需要先导入一个模块 print(reduce(lambda x,y:x+y,l,10)) # 初始值为10,初始值就是第一个参数 # 有初始值的时候,第一次获取一个值然后相加,之后每次获取一个值与上一次相加的结果再相加