函数扩展
函数递归
二分法
列表生成式
字典生成式
匿名函数
常用的内置函数
函数递归:函数在调用阶段直接或间接调用自身.如:
def func(n): print('from func',n) func(n+1) func(1)
def index(): print('from index') login() def login(): print('from login') index() login()
上述两个例子分别是直接调用自身以及间接调用,但是这样的函数会一直重复下去,不应这样.但递归函数可以帮助我们
递归分为两个阶段:
1.回溯:一次次重复,但是这个重复必须每一次重复问题的复杂度都应该下降,到有一个最终的结束条件 当遇到终止条件,则从最后往回一级一级的把值返回来。
2.递推:一次次往回推导的过程 递归每一次都是基于上一次进行下一次的执行。递归必须要有一个明确的结束条件, 否则就变成死循环
# 年龄的递归函数 def age(n): if n == 1 : # 结束的条件必须有 return 18 return age(n-1) + 2 # 每次离确定值都更进一步 res = age(5) print(res) # 首先第一步是执行函数age(5),返回的是age(4)+2 # 接着执行的是age(4),返回的是age(3)+2 # 接着执行的是age(3),返回的是age(2)+2 # 接着执行的是age(2),返回的是age(1)+2 # 接着执行的是age(1),返回的是18 # 再然后递推: # age(2) = age(1) + 2 # age(3) = age(2) + 2 # age(4) = age(3) + 2 # age(5) = age(4) + 2 # age(5) = age(1) + 2 + 2 + 2 + 2 = 26
打印列表中的数字 l = [1,[2,[3,[4,[5,[6,[7,[8,[9]]]]]]]]
# 第一种方法: l = [1,[2,[3,[4,[5,[6,[7,[8,[9]]]]]]]] for i in l: if type(i) is int: print(i) else: for j in i: if type(j) is int: print(j) else: for k in j: if type(k) is int: print(k) else: ... # 和pass一样的作用
在不知道列表包含多少数字的时候需要无限循环写下去,即使知道,也很繁琐,因此我们可以运用递归函数.
递归函数不用考虑循环次数,只要把握好结束的条件就好.
# 第二种方法 l = [1,[2,[3,[4,[5,[6,[7,[8,[9]]]]]]]] def get_num(l): for i in l: # 自带结束功能 if type(i) is int: # 每次取出int,留下小列表 print(i) else: get_num(i) # 每次将小列表重复取值
get_num(l)
小结:
1.递归函数的定义 :一个函数在执行的过程中调用了自己
2.递归在python中的最大深度 : 1000/998
3.递归的最大深度是可以自己修改的,但是不建议你修改
二分法:运用二分法时候,容器类型里面的数字必须有大小顺序;二分法可以提高解决问题的效率.(掐头结尾取中间,必须是有序序列,数据量越大,效率约明显)如:
普通取值:
num = 123 l = [1,3,5,12,57,89,101,123,146,167,179,189,345] for i in l: if num == i: print('找到了') # 可以看到,虽然最终也能找到目标数字,但是找寻次数多,若果目标数字在最后,那么就需要经历全部循环才能找到,效率不高.
二分法取值:
l = [1,3,5,12,57,89,101,123,146,167,179,189,345] num = 189 def wanted_num(l,num): if not l: print('不在列表中') return print(l) # 重复打印每次切取后的列表 middle_index = len(l) // 2 if num > l[middle_index]: # 与中间的值比大小 l1 = l[middle_index + 1:] # 因为与中间值大,所以不需要再将其切取进去,范围往后移一位 wanted_num(l1,num) else num < l[middle_index]: l2 = l[0:middle_index] # 比中间值小,在左边切取,顾左不顾右原则,范围取0到中间值 wanted_num(l2,num) else: print('找到了',num) wanted_num(l,num)
# 结果:
[1, 3, 5, 12, 57, 89, 101, 123, 146, 167, 179, 189, 345]
[123, 146, 167, 179, 189, 345]
[189, 345]
[189]
找到了 189
三元表达式:
固定表达式: 值1 if 条件 else 值2
(条件成立,值1; 条件不成立,值2) 三元表达式推荐只有两种情况的可能下使用
# 例子: def my_max(x,y) if x > y : return x return y # 就相当于: res = x if x > y else y
列表生成式:
l = ['a','b','c'] # 需求,在每个元素后面加上* # 第一种方法:普通法 l1 = [] # 定义了一个空列表 for element in l : l1.append('%s*'%element) # %s占位,由后面的元素挨个赋值 print(l1) # 结果为:['a*', 'b*', 'c*'] # 第二种方法:列表生成式 res = ['%s*'%name for name in l] print(res) # 结果为:['a*', 'b*', 'c*'] # 可以看到,两种方法结果一致.可以这样理解: # 1.先for循环依次取出列表里面的每个元素 # 2.然后把每次取出的值交给前面的代码
第一种方法使用for循环和append添加完成需求,很容易理解,也容易实现,但是和第一种方法相比,使用列表生成式实现功能只需要一行代码就可以搞定.
字典生成式:
方法一: l1 = ['a','b','c'] l2 = [1,2,3] # 需求:将l1与l2的元素一一对应起来,生成一个字典 dict = {} for i,j in enumerate(l1): dict[j] = l2[i] # dict[j]是字典的key,l2[i]是列表l2中的一个个元素,它们相等,则有了对应关系 print(dict) # 结果为{'a': 1, 'b': 2, 'c': 3} # 方法二: l1 = ['jason','123','read'] d = {i:j for i,j in enumerate(l1) if j != '123'} print(d) # 结果为:{0: 'jason', 2: 'read'} # 可以理解为: # 1.i,j分别代表列表l1的索引和值,for循环依次取出j # 2.判断j是否为123,若成立,则赋值给前面的j,不是则直接舍弃掉 # 3.字典d中i和j的关系相当于key-value
跟列表生成式一样,字典生成式用来生成字典,不同的是,字典需要两个值
此外,还有集合生成式等;如: 也与列表生成式类似,不过用的是{}
res = {i for i in range(10) if i != 4}
print(res) # {0, 1, 2, 3, 5, 6, 7, 8, 9}
匿名函数:
没有名字的函数 临时存在的 用完就没了 匿名函数自带return,而return的结果就是表达式的计算后的结果
def my_sum(x,y): renturn x+y my_sum(1,2) func = lambda x,y:x+y print(func(1,2)) # 3
res = (lambda x,y:x+y)(1,2) # 蓝色代表左边
print(res) # 3
# lambda后面的左边相当于函数的形参 # lambda后面的右边相当于函数的返回值 # 匿名函数通常不会单独使用,是配合内置函数一起使用的
匿名函数的使用和普通的函数其实是一样的,唯一的区别就是在于普通函数往往用来去处理一些比较复杂的程序逻辑,而匿名函数则仅仅是处理功能非常简单的逻辑。
常用的内置函数:map / zip / filter / sorted / reduce
# max:取出容器类型元素最大值(基于for循环)
map映射: map后面接收一个函数和一个列表,并通过for循环把函数依次作用在列表上,得到一个新列表
l = [1,2,3,4,5,6] print(list(map(lambda x:x+5,l))) # 基于for循环 [6, 7, 8, 9, 10, 11]
zip拉链:用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
并且如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同
l1 = [1,2,] l2 = ['jason','egon','tank'] l3 = ['a','b','c'] print(list(zip(l1,l2,l3))) # [(1, 'jason', 'a'), (2, 'egon', 'b')] 基于for循环
filter过滤:用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。
可接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判断,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。
l = [1,2,3,4,5,6] print(list(filter(lambda x:x != 3,l))) # 基于for循环 [1, 2, 4, 5, 6]
sorted排序:对所有可迭代的对象进行排序操作,返回的是一个新的 list,而不是在原来的基础上进行的操作。
l = ['jason','egon','nick','tank'] print(sorted(l,reverse=True)) # ['tank', 'nick', 'jason', 'egon'] 又进行了一次反转 # 首字母的排列顺序 A-Z 65-90 a-z 97-122
reduce:对参数序列中元素进行累积。
函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果
from functools import reduce l = [1,2,3,4,5,6] print(reduce(lambda x,y:x+y,l,19)) # 40