递归函数和匿名函数
1 递归
1.1 递归的应用场景
递归是一种编程思想,应用场景:
-
在我们日常开发中,如果要遍历一个文件夹下面所有的文件,通常会使用递归来实现;
-
在后续的算法课程中,很多算法都离不开递归,例如: 快速排序。
1.1.1 递归的特点
- 函数内部自己调用自己
- 必须有出口
1.2 应用:3 以内数字累加和
def sum_num(num):
if num == 1:
return 1
# 由于 3 到 1 需要减两次,那么就需要递归执行两次 sum_num(num - 1)
# 第一次递归 num = 3 - 1 = 2 ,此时 return = 3 + 2 = 5
# 第二次递归 num = 2 - 1 , if 条件触发 return = 5 + 1 = 6
return num + sum_num(num - 1)
totol = sum_num(3)
print(totol)
[10:25:45 root@dev py-demo]#/bin/python3 /root/py-demo/day-1/test.py
6
1.2.1 递归函数执行流程:
- 当执行
sum_numbers(3)
后程序就开始调用sum_numbers(num)
函数,通过if
判断程序并没触发num==1
,那么就直接执行return num + sum_numbers(num-1)
在次执行第二次的sum_numbers(num)
sum_numbers(num -1)
此时num = 3 - 1 = 2
if
判断程序并没触发 ,那么就直接执行return num + sum_numbers(num-1)
sum_numbers(num -1)
此时num = 2 - 1 = 1
if
判断触发,return 1
给步骤 2 ,此时在步骤 2 中num = 2 + 1 = 3
,紧接着步骤 2 将return num + sum_numbers(num-1) = 3 + 3 = 6
结果return
给步骤 1-
此时
sum_numbers(3) = 6
以上就是程序递归函数的整个流程
1.2.2 递归出口
递归我们都知道有两个特点:
- 函数内部自己调用自己
- 递归必须要有出口
假如我们在递归函数没有添加递归出口那会出现什么问题呢?
def sum_num(num):
# 递归程序出口
# if num == 1:
# return 1
return num + sum_num(num - 1)
totol = sum_num(3)
print(totol)
在上面代码中我将 if
递归函数程序出口注释掉,程序就会立马报错
[10:25:45 root@dev py-demo]#/bin/python3 /root/py-demo/day-1/test.py
Traceback (most recent call last):
File "/root/py-demo/day-1/test.py", line 8, in <module>
totol = sum_num(3)
File "/root/py-demo/day-1/test.py", line 6, in sum_num
return num + sum_num(num - 1)
File "/root/py-demo/day-1/test.py", line 6, in sum_num
return num + sum_num(num - 1)
File "/root/py-demo/day-1/test.py", line 6, in sum_num
return num + sum_num(num - 1)
[Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceeded
# 直接报错,报错位置都是分别带有函数递归的位置
# maximum recursion depth exceeded:超出最大递归深度,这里为 996
所谓的递归深度,就是函数自己调用自己的次数,并不会像死循环一直调用,所以在工作中写递归函数的时候需要提前写好递归出口
2 lambda 表达式
lambda
在 python 中用于定义匿名函数,从而实现
2.1 lambda 的应用场景
如果一个函数有一个返回值,并且只有一句代码,可以使用 lambda 简化
但是我们都知道当我们开辟函数的时候都需要有一块内存用来存储,所以 lambda 也是如此也需要有一个块内存空间用来做存储,但是在普通函数执行是占用的内存空间要大于 lambda 执行时的内存空间
也就是说如果使用 lambda 就会让服务器的负载以及资源减轻,也能减少程序员的代码量
2.2 lambda 语法
lambda 参数列表: 表达式
注意:
- lambda 表达式的参数可有可无,函数的参数在 lambda 表达式中完全适用。
- lambda 表达式能接收任何数量的参数但只能返回一个表达式的值。
2.2.1 快速入门
# 传统函数
def fn1():
return 200
# 输出 function
print(fn1)
# 输出 200
print(fn1())
# 通过 lambda 定义 fn2 匿名函数,并且返回值为 100
fn2 = lambda: 100
# 输出 <function <lambda> 说明 fn2 是匿名函数类型, <lambda>
print(fn2)
# 输出 100
print(fn2())
[14:16:00 root@dev py-demo]#/bin/python3 /root/py-demo/day-1/test.py
<function fn1 at 0x7f2cc038f310>
200
<function <lambda> at 0x7f2cc020fd30>
100
注意:
直接打印 lambda 表达式,输出的是此 lambda 的内存地址
2.3 示例:计算 a + b
2.3.1 函数实现
# 通过传统函数实现
def add(a,b):
return a+b
print(add(1,2))
注意:
可以看到我们通过两行代码实现了 add 函数的功能
2.3.2 lambda 实现
# add = lambda 定义 add 匿名函数
# a , b 定义匿名函数 add 的形参
# : a + b 返回 a + b
add = lambda a , b : a + b
print(add(1,2))
[14:24:22 root@dev py-demo]#/bin/python3 /root/py-demo/day-1/test.py
3
2.4 lambda 的参数形式
2.4.1 无参数
fn1 = lambda: 100
print(fn1())
[15:29:43 root@dev py-demo]#/bin/python3 /root/py-demo/day-1/test.py
100
2.4.2 一个参数
如果当 lambda 有参数,那么在函数调用的时候一定要传入数据
# 定义匿名函数 lambda, 接收形参 a 返回值为 a
fn1 = lambda a : a
print(fn1('hello world!'))
[09:18:56 root@dev py-demo]#/bin/python3 /root/py-demo/day-1/test.py
hello world!
2.4.3 默认参数
默认参数还有另外一个名字叫做缺省参数,所谓的默认参数指的就是带有默认值的参数,这种参数的特点就是当函数调用的时候,可为默认参数传值也可以不传值,如果为默认参数传值那么就覆盖原有默认参数,而是用新数据,如果不传值我们的程序也不会报错
# 这里通过 lambda 定义形参,而且给 c 定义默认值为 100
fn1 = lambda a , b , c = 100: a + b + c
print(fn1(10,20))
[09:44:39 root@dev py-demo]#/bin/python3 /root/py-demo/day-1/test.py
130
2.4.4 可变参数 *args
*args 用来接收我们不定长的位置使用,返回的值为元组
fn1 = lambda *args : args
print(fn1(10,20,30))
[09:44:50 root@dev py-demo]#/bin/python3 /root/py-demo/day-1/test.py
(10, 20, 30)
2.4.5 可变参数 **kwargs
接收不定长关键字参数,返回字典
# 接收 name = tome ,age = 10
fn1 = lambda **kwargs : kwargs
print(fn1(name="tome",age=10))
[09:53:28 root@dev py-demo]#/bin/python3 /root/py-demo/day-1/test.py
{'name': 'tome', 'age': 10}
2.5 lambda 应用
2.5.1 带判断的 lambda
通过 if
进行判断
# a if a > b else b 三目运算,if 判断 a > b 为真就返回 a ,否则返回 b
# 因为条件成立的返回值是最前面的那个参数
# else 后面就是跟的条件不成立返回值
fn1 = lambda a , b : a if a > b else b
print(fn1(10,20))
# 返回 20 传入给 b 值比 a 值大
[09:53:39 root@dev py-demo]#/bin/python3 /root/py-demo/day-1/test.py
20
2.5.2 列表数据按字典 key 的值排序
需要实现将列表里面的字典数据进行排序,排序的基准是按照字典的某个 key 值进行升序或降序排序,在工作中一般用于用户的个人信息进行存储,通过 name
字段进行排序,也可以通过 age 等其他字段进行排序
students = [
{'name':'tom','age' : 18},
{'name':'ayn','age' : 17},
{'name':'ste','age' : 19},
{'name':'mot','age' : 20},
]
# 通过 students.sort 内置函数进行排序,这里通过 key 为 name 进行排序
# key 为一个 lambda 匿名函数的表达式
# lambda x ,这里的 x 是表示用来升序或者降序的排序,而在这里就是一个字典
students.sort(key=lambda x : x['name'])
print(students)
# 年龄升序排序
students.sort(key= lambda x : x['age'])
print(students)
# 降序通过 reverse = True 实现降序排序反转,如果不屑 reverse 默认为升序
students.sort(key= lambda x : x['name'],reverse= True)
print("name 降序:\n",students)
students.sort(key= lambda x : x['age'],reverse= True)
print("age 降序:\n",students)
[10:48:29 root@dev py-demo]#/bin/python3 /root/py-demo/day-1/test.py
[{'name': 'ayn', 'age': 17}, {'name': 'mot', 'age': 20}, {'name': 'ste', 'age': 19}, {'name': 'tom', 'age': 18}]
[{'name': 'ayn', 'age': 17}, {'name': 'tom', 'age': 18}, {'name': 'ste', 'age': 19}, {'name': 'mot', 'age': 20}]
name 降序:
[{'name': 'tom', 'age': 18}, {'name': 'ste', 'age': 19}, {'name': 'mot', 'age': 20}, {'name': 'ayn', 'age': 17}]
age 降序:
[{'name': 'mot', 'age': 20}, {'name': 'ste', 'age': 19}, {'name': 'tom', 'age': 18}, {'name': 'ayn', 'age': 17}]