递归&二分法&三元表达式&生成式&匿名函数
1. 递归函数
递归:函数在运行过程中,直接或间接的调用了自身。
# 关于递归深度
# 官网表述:python默认的最大递归深度为1000次,代码跑出来可能997,998.
# 查看最大递归深度
import sys
print(sys.getrecursionlimit())
# 更改最大递归深度
sys.setrecursionlimit(2000)
# 直接调用自身
def index():
print('from index')
index()
index()
# 间接调用自身
def func():
print('from func')
test()
def test():
print('from test')
func()
func()
但是以上两种情况都没有什么意义。
递归分为两个阶段:
- 递推
- 一层层往下推到答案(每次递推之后复杂度相较于上一次一定要有所下降)
- 回溯
2. 根据最后的结论往前推导出最初需要的答案。
注意:递归一定要有结束条件!!!!!!!
# 伪代码:可能无法运行,但是可以表达逻辑
age(5) = age(4) + 2
age(4) = age(3) + 2
age(3) = age(2) + 2
age(2) = age(1) + 2
age(1) = 18
def get_age(n):
# 递归要有结束条件
if n == 1:
return 18
return get_age(n-1) + 2
print(get_age(5))
# 这是递归函数真正的用途
举例
l = 1,[2,[3,[4,[5,[6,[7,[8,[9,[10,]]]]]]]]]
# 要求:打印出列表种每一个数字
def get_num(lis):
for i in lis:
if type(i) is int:
print(i)
return get_num(i)
get(l)
# 因为for循环列表种没有元素之后会自动停止,所以不用额外加上结束条件。
2. 算法之----二分法
什么是算法????
解决问题的最佳(高效)方法。
# 二分法能够使用的场景:数据集必须有序.
l1 = [3,9,12,23,35,42,56,64,77,89,94,108,112,120,139,147,158,169,173]
# 要求:在列表中找出目标数字
# 二分法的思维,将数据集一分为二,不断重复,直到找到目标。
def find_num(target_num, lis):
# 还要想到一种情况:目标数字不在列表当中
if len(lis) == 0: # 列表找空了,没找到
print('没有找到target_num:{}'.format(target_num))
return
# 先获取中间位置的索引值
mid_index = len(lis)//2
# 判断目标数字与中间位置索引对应的数字大小关系
if target_num > lis[mid_index]:
# 说明目标数字在列表中间索引右侧
lis_r = lis[mid_index + 1: ] # 切片取值
# 继续调用该函数
find_num(target_num,lis_r)
elif target_num < lis[mid_index]:
# 说明目标数字在列表中间索引左侧
lis_l = lis[: mid_index] # 切片取值
# 继续调用该函数
find_num(target_num,lis_l)
else:
# 中间索引值对应数字恰好是目标数字
print('找到了target_num:{}'.format(target_num))
find_num(42, l1)
# 找到了target_num:42
find_num(111, l1)
# 没有找到target_num:111
3. 三元表达式(三目运算)
def my_max(a, b):
if a > b:
return a
else:
return b
# 当功能需求仅仅是二选一的情况下,则推荐使用三元表达式
def my_max(a, b):
return a if a > b else b
"""
条件成立取的值 if 条件 else 条件不成立取的值
三元表达式尽量不要嵌套使用,本身就是为了简洁,不要搞复杂了。
"""
is_free = input('电影是否收费(y/n)>>>:').strip()
print('收费' if is_free == 'y' else '免费')
4. 生成式
-
列表生成式
# 传统方法 name_list = ['jason', 'jack', 'joshua', 'tony'] # 要求给列表中所有的人名加上_DSB后缀 # 1. 定义一个空列表 new_list = [] # 2. 循环旧列表 for name in name_list: new_name = '{}_DSB'.format(name) new_list.append(new_name) # 列表生成式做法 lis_method = [ '{}_DSB'.format(name) for name in name_list] print(lis_method) # 将列表中所有的人名后面加上_DSB,jason除外,打印出其他人 res = ['{}_DSB'.format(name) for name in name_list if name != 'jason'] print(res) # 这已经是最复杂的情况了 # 因为for循环和if 都可以和else一起用,所以此处后面不能加else了。
-
字典生成式
枚举法enumerate
针对该方法使用for循环取值,每会产生两个结果
第一个是从0开始的数字
第二个是被循环对象里面的元素
还可以通过start参数控制起始数字li = ['jason', 'joshua', 'jack', for i, j in enumerate(li): print(i, j) """ 0 jason 1 joshua 2 jack 3 alex 4 tony """ for k, v in enumerate(li, 2): print(k, v) """ 2 jason 3 joshua 4 jack 5 alex 6 tony """
正题
name_list = ['jaosn','jack','tony','joshua'] res = {i:j for i,j in enumerate(name_list if j == 'jason')} print(res) # 同理集合也有生成式 # 只有元组是特殊的,生成一个迭代器。后面会说到。
5. 匿名函数
顾名思义就是没有名字的函数
# 语法格式
lambda 形参: 返回值
print( (lambda x: x**2)(2))
# 4
# map() 映射
"""
map函数的原型是map(function, *iterables),它的返回结果是一个列表。
参数function传的是一个函数名,可以是python内置的,也可以是自定义的。
参数iterable传的是一个可以迭代的对象,例如列表,元组,字符串这样的。可以支持传多个可迭代对象。
这个函数的意思就是将function应用于iterable的每一个元素,结果以列表的形式返回。
"""
l = [1, 2, 3, 4, 5, 6, 7, 89,]
print(list(map(lambda x: x**2, l))
# [1, 4, 9, 16, 25, 36, 49, 7921]