1.函数递归
什么是函数递归
函数递归是函数嵌套的一种,是在函数调用阶段,直接或者间接的又调用自身
函数递归的演示
直接调用自身
def func(n): print('递归函数的演示%s'%n) print(n) func(n+1) # 又调用了本身 func(1)
间接调用自身
# index()函数内部调用了func()函数 def index(n): print(n) func(n+1) print(n) # func()函数内部又调用了index()函数,导致了递归出现了死循环 def func(n): print(n) index(n+1) index(1)
在函数内部又调用了自身,导致了重复调用,类似死循环,但是为了防止内存的溢出,python解释器对函数的递归做了限制,大概只能递归998次左右
我们可以通过添加sys模块人为的更改递归的限制此时
# sys模块 import sys print(sys.getrecursionlimit()) # 输出递归限制 sys.setrecursionlimit(2000) # 可以更改递归限制
函数递归的运用
递归可以在函数内帮我们完成类似循环的操作,但是我们不可能让一个函数无限制的递归下去,这时候我们需要给递归限制一个条件
递归分为两个阶段
回溯:函数递归时必须有一个明确的结束条件,并且每次递归的问题复杂程度慢慢下降,这样才能解决问题,否则便是毫无意义的死循环
递推:到达结束条件之后,一步步的往回推,获取最终结果
问题1:第一个人是20岁,他比第二个人小2岁,以此类推第10个人是多少岁
''' age1 = 20 age2 = age1 + 2 age3 = age2 + 2 age4 = age3 + 2 ... age(n) = age(n-1) + 2 ''' def index(n): if n == 1: # 结束条件 return 20 return index(n-1)+2 res = index(10)
问题2:循环输出l = [1,[2,[3,[4,]]]]
l = [1,[2,[3,[4,]]]] for i in l: if type(i) is int: print(i) else: for i1 in i: if type(i1) is int: print(i1) else: for i2 in i1: if type(i2) is int: print(i2) else: for i3 in i2: if type(i3) is int: print(i3)
可以使用for循环来输出,但是这样做很繁琐,一旦数字过大,便很难输出结果
利用递归解决
def index(l): for i in l: if type(i) is int: print(i) else: index(i) index(l)
注意:
使用递归函数不要考虑循环的次数 只需要把握结束的条件即可
2.算法之二分法
什么是算法
算法是解决问题高效的方法
问题:求一个数是否在一个列表中
l = [1,2,3,4,5,6,7,8,9] x = 9 print(x in l) # 第一种 for i in l: # 第二种 if x == i: print('%s在列表中'%x) else: pass
这两种方法都是基于for循环,即把每个数字都取出来一个个的进行对比,如果要求的是最后一个数字,则需要比较9次,这样的效率比较低
二分法查找:在有序列表中,先求出列表中间那个数,与被比较数比较,如果大于被比较数,则把小于中间数的数字作为列表,再求这个列表的中间数,再进行比较,直至找到这个数,这样的方法查找次数减少,查找效率提高
用二分查找法查找一个数
l = [1,2,3,4,5,6,7,8,80,100] def index(x,l): if not l: print('%s这个数不在列表中'%x) return key = len(l)//2 # 求列表中间的索引 if x > l[key]: # 与列表中间索引对应的值进行比较 l_right = l[key + 1:] # 比中间的值大就取右半区 index(x,l_right) elif x < l[key]: l_left = l[0:key] # 比中间的值小就取左半区 index(x,l_left) else: print('%s在列表中'%x) # 相等就打印 index(80,l)
注意:用二分法查找的列表一定是有大小顺序的
3.三元表达式
函数求数字大小
def my_max(x,y): if x > y: return x else: return y res = my_max(5,9) print(res)
三元表达式求数字大小
x = 4 y = 3 res1 = x if x > y else y # 三元表达式表示的是如果条件成立就返回x,条件不成立就返回y print(res1)
三元表达式的固定格式
# 三元表达式的格式: 值/代码1 if 布尔值判断 else 值/代码2 如果条件成立布尔值为True 则 输出值/代码块1 如果条件不成立布尔值为False 则 输出值/代码块2
注意:三元表达式只推荐在只有两个情况的条件下使用,一旦超过两个情况,代码块会变得复杂,不适合使用
4.列表生成式
输出一个新列表,并且在每个元素后面添加123
l = ['sss','xxx','ccc','111'] # 普通的方法 l1 = [] for name in l: l1.append('%s123'%name) # 循环输出每个元素,并在每个字符串后面添加123,再添加入新列表 print(l1)
用列表生成式,在每个元素后面添加1234
# 列表生成式的方法 l1 = ['%s1234' %name for name in l] # 直接用列表生成式生成新列表 print(l1)
列表生成式后也可以跟if判断式
l2 = ['%s' %name for name in l1 if name.isdigit() == False] # 把不是纯数字的元素添加到新列表中 print(l2)
先for循环输出列表中的每个元素
交由if判断,条件成立的元素放入新列表
条件不成立的元素直接舍弃
注意:if后面不能再跟else,因为for后面也有else的说法,这样程序不能判断是for的else还是if的else
5.字典生成式和集合生成式
传统方法把两个列表一一对应生成一个字典
# 字典集合生成式 l1 = ['name','pwd','age'] l2 = ['sxc','123','18','123'] d = {} for i,j in enumerate(l1): # 枚举,i相当于列表的索引,j是列表的元素 print(i,j) d[j] = l2[i] print(d)
字典生成式
d1 = {i:j for i,j in enumerate(l1,1)} # 字典生成式生成列表 print(d1) d2 = {i:j for i,j in enumerate(l2,1) if i != 2} # 加if判断条件的表达式,把i==2的情况去掉,后面也不能跟else print(d2)
注意:和列表生成式类似,字典生成式后也可以跟if判断条件,也不能再跟else
集合生成式
s1 = {i for i in range(10)} # 集合生成式 print(s1) s2 = {i for i in range(10) if i != 5} # 集合生成式加if判断条件,后面也不能跟else print(s2)
注意:和列表生成式类似,集合生成式后也可以跟if判断条件,也不能再跟else
生成式表达式:没有元组生成式,只有生成式表达式(相当于一个老母猪)
t1 = (i for i in range(10) if i != 6) # 这样写不是元组生成式,而是生成器表达式,相当于老母猪 print(t1) for i in t1: print(i)
6.匿名函数
匿名函数不再使用def的标准定义一个函数,而是使用lambda来创建匿名函数,匿名函数顾名思义是没有函数名的函数
匿名函数有自己的名称空间,并且只能访问自己参数列表的名称,不能访问其他或者全局名称空间的名称
匿名函数lambda只是一个表达式,函数体比def简单的多,并且他只能封装有限的逻辑表达式
匿名函数的特点:临时存在,用完就没了
求两个数的和
def sum(x,y): return x + y res = sum(1,2) print(res)
匿名函数求和
res1 = (lambda x,y:x+y)(3,4) # 匿名函数的第一种写法 print(res1) res3 = lambda x,y:x+y # 匿名函数的第二种写法 print(res3) # 这是函数对应的地址空间 print(res3(5,6))
匿名函数的语法:(匿名函数lambda 匿名函数对应的形参 : 匿名函数对应的返回值)(匿名函数的实参)
匿名函数通常不会单独使用,是配合内置函数一起使用的
7.常用的内置函数
Python内置函数有很多
常用的一共约有69个内置函数
max()函数
max(x,y,z...) 方法返回给定参数的最大值,参数可以为序列,内部是基于for循环的
l = [1,2,3,4,5] print(max(l)) # 求最大值,内部是基于for循环的
max()+内置函数lambda的运用
d = { 'sxc':30000, 'zzj':88888888888, 'zzp':3000, 'lzx':1000 } # 求value的最大值,返回对应key的值 print(max(d,key = lambda name :d[name])) # 求value的最小值,返回对应key的值 print(min(d,key = lambda name :d[name]))
map(函数,一个或多个序列)映射
按照序列的索引执行前面的函数
l1 = [1,2,3,4,5] l2 = [5,4,3,2,1] res = map(lambda x,y:x+y,l1,l2) # 定义一个匿名函数,输入两个列表按照索引执行函数 print(list(res))
zip(可迭代的对象)拉链
把多个迭代器内的内容按照索引分别组合成一个个元组,也是基于for循环的
l1 = ['姓名:sxc','姓名:zzj','姓名:zzp'] l2 = ['年龄:18','年龄:19','年龄:20'] l3 = ['密码:123','密码:234','密码:345'] res = zip(l1,l2,l3) print(res) # 老母猪 print(list(res)) # 可以用list来转换输出列表
filter(判断布尔值的函数,可迭代的对象)
用函数判断可迭代的对象的True和False,True的输出,False的丢弃
l = [9,7,5,3,1] res = filter(lambda x:x > 4,l) # 输出布尔值为True的l中的元素 print(res) print(list(res))
sorted(可迭代对象,key,reverse)升序,降序
对可迭代对象的升序降序,reverse = True降序,reverse = False升序
sorted与list.sort的不同是前者重新创建了一个列表,后者把原列表重新声明了,相当于修改了原列表
l = [1,2,3,4,5,6] res = sorted(l,reverse=True) # 降序 print(res)
reduce(函数,可迭代对象,初始值) 函数会对参数序列中元素进行累积
两个及以上的可迭代对象的数据按照函数累积,可以指定初始值
from functools import reduce l = [1,2,3,4,5,6] res = reduce(lambda x,y:x+y,l) # 不指定初始值1+2+3+4+5+6 print(res) res1 = reduce(lambda x,y:x+y,l,100) # 初始值指定为100,100+1+2+3+4+5+6 print(res1)
12