# 递归
递归是什么?
举个例子:
def demo(n:int): | |
count = 1 | |
if n ==100: | |
return count | |
else: | |
return count + demo(n+1) | |
print(demo(2)) # 输出 99 |
约等于循环 99 次 + 1
在函数中调用函数本身就是递归
递归必须要准备一个退出分支,例如本段的 if n==100:
就是退出分支
如果没有退出分支:
def demo(n:int): | |
count = 1 | |
return count + demo(n+1) | |
# RecursionError: maximum recursion depth exceeded |
python 有最大递归深度,一般为 1000 层,部分解释器由于配置可能会有 ±10 层的区别
假如这个函数在正常情况的递归深度超过了 1000 层,可以使用下面的代码调整最大深度
import sys | |
sys.setrecursionlimit(10000) # 层数 |
然后你就会发现:代码执行不完就会报错 进程已结束,退出代码-1073741571 (0xC00000FD)
这是因为栈溢出了,建议减少递归层数或进行尾递归优化
生成器在后面会讲到
# 匿名表达式和函数变量
# 匿名表达式
a = lambda n: n * 10 | |
print(a(10)) |
这种写法 PEP 并不建议,它会建议使用 def 来实现效果,但部分情况下这样会徒增行数
并不会增加可读性
匿名表达式格式: lambda 输入:输出
建议将 lambda 用于简易函数,大型函数使用 def
# 警卫
在 lambda 后可以使用 if...else
(警卫) 来实现分支结构
例子:
f = lambda a: a*10 if a%2 == 0 else a*5 | |
print(f(10)) | |
print(f(5)) |
警卫的格式: 返回值 if 条件 else 返回值(可以再套一个if)
可用于 return
等返回值的关键字后
套的层多了可读性很差
# 函数变量
def demo(): | |
print("hello") | |
func = demo | |
func() |
变量名 = 方法
即为函数变量格式
方法后不带括号,不然就是把返回值作为赋值对象
直接用 变量名()
就可以调用方法
# 推导式
f = [x for x in range(10)] | |
print(f) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] |
推导式格式: 表达式 for 变量 in 可迭代数据
警卫同样适用于表达式,如下:
f = [x*2 if x%2 == 0 else x for x in range(10)] | |
print(f) |
# 迭代器和生成器
# 迭代器
list1 = [1,2,3,4,5] | |
iter1 = iter(list1) # 或 list1.__iter__() | |
print(iter1.__next__()) # 或 next (iter1) |
对可迭代对象执行 iter()
操作,就可以得到一个迭代器
对迭代器执行 next()
方法,就会让指针前进一项并返回
在指针超出范围后,会返回 StopIteration
错误
迭代器非常省内存,比如一个有一千万个整数的列表,使用列表会占用 100MB 左右,而迭代器只有 50B 左右
因为迭代器是惰性的,执行前不会访问
可以使用 for 循环来快速访问迭代器:
l = [1,2,3,4,5] | |
i = iter(l) | |
for j in i: | |
print(j) |
# 生成器
# 生成器函数
def fibonacci(num: int): | |
a, b = 1, 1 | |
for i in range(num - 1): | |
a, b = b, a + b | |
yield a |
这是一个生成斐波那契数列的函数,尝试直接 print 它:
print(fibonacci(10)) |
返回: <generator object fibonacci at 0x0000022C97099B60>
实际上这个函数已经变成了生成器,可以使用 for 或 next 来获取返回值
生成器的语法:
def 函数名(参数): | |
语句 | |
yield 返回值 | |
语句 |
与 return 不同,函数遇到 yield 后不会退出,在返回值后继续执行下面的代码
所以可以有多个 yield, 返回值格式如下:
值 1 值 2 值 3 值 1 值 2 值 3... |