函数递归及匿名函数

递归Recursion

  • 函数直接或者间接调用自身就是递归

  • 递归需要有边界条件, 递归前进段, 递归返回段

  • 递归一定要有边界条件

  • 当边界条件不满足的时候, 递归前进 * 当边界条件满足时、 递归返回

  • 递归要求:

  • 递归一定要又推出条件, 递归调用一定要执行到这个退出条件。 没有退出条件的递归调用, 就是无限调用

  • 递归调用的深度不宜过深

  • python对递归调用的深度做了限制, 以保护解释器

  • 超过递归深度限制,抛出RecursionError: maxinum recursion depth exceeded 超出最大深

  • sys.getrecursionlimit()

递归的性能 fib35项比较

 for 循环
import datetime
start = datetime.datetime.now()
a = 0
b = 1
n = 35
循环实现
for i in range(n - 1):
a, b = b, a + b
else:
pass #print(b) 9227465
delta = (datetime.datetime.now() -
start).total_seconds()
print(delta)

递归
import datetime
n = 35
def fib(n):
return 1 if n < 3 else fib(n-1) + fib(n-2)
start = datetime.datetime.now()
fib(35)
delta = (datetime.datetime.now() -
start).total_seconds()
print(delta)

递归的性能
1.循环稍微复杂一些,但是只要不是死循环,可以多次迭代直至算出结果
2.fib函数代码极简易懂,但是只能获取到最外层的函数调用,内部递归结果都是中间结果。而且给定一个n
都要进行近2n次递归,深度越深,效率越低。为了获取斐波那契数列需要外面再套一个n次的循环,效率就更低了
3.递归还有深度限制,如果递归复杂,函数反复压栈,栈内存很快就溢出了
4.思考:这个极简的递归代码能否提高性能呢? 递归的性能
 斐波那契数列的改进
1、def fib(n, a=0, b=1):
2、a, b = b, a+b
3、if n == 1:
4、return a
5、return fib(n-1, a, b)
6、print(fib(4))

 改进
1、左边的fib函数和循环的思想类似
2、参数n是边界条件,用n来计数
3、上一次的计算结果直接作为函数的实参
4、效率很高
5、和循环比较,性能相近。所以并不是说递归一定
效率低下。但是递归有深度限制
6、对比一下三个fib函数的性能

递归
 间接递归
def foo1():
foo2()
def foo2():
foo1()
foo1()
间接递归,是通过别的函数调用了函数自身
但是,如果构成了循环递归调用是非常危险的,但是往往这种情况在代码复杂的情况下,还
是可能发生这种调用。要用代码的规范来避免这种递归调用的发生

递归总结
 递归是一种很自然的表达,符合逻辑思维
 递归相对运行效率低,每一次调用函数都要开辟栈帧
 递归有深度限制,如果递归层次太深,函数反复压栈,栈内存很快就溢出了
 如果是有限次数的递归,可以使用递归调用,或者使用循环代替,循环代码稍微复杂一些,但是只要不是
死循环,可以多次迭代直至算出结果
 绝大多数递归,都可以使用循环实现
 即使递归代码很简洁,但是能不用则不用递归
每一次函数调用都是不同的
间接递归: def foo1():
foo2()
def foo2():
foo1()
匿名函数
匿名:隐藏名字,即没有名称
匿名函数:没有名字的函数。
Lambda表达式
在这里插入图片描述

  1. 使用lambda关键字定义匿名函数,格式为 lambda参数列表: 表达式
  2. 参数列表不需要小括号。无参就不写参数
  3. 冒号用来分割参数列表和表达式部分
  4. 不需要使用return。表达式的值,就是匿名函数的返回值。表达式中不能出现等号
  5. lambda表达式[匿名函数]只能写在一行上,也称为单行函数
  6. 匿名函数往往用在为高阶函数传参时,使用lambda表达式,往往能简化代码

生成器generato

  • 生成器指的是生成器对象,可以由生成器表达式得到,也可以使用yield关键字得到一个生成器函数,调用这
    个函数得到一个生成器对象
  • 生成器对象,是一个可迭代对象,是一个迭代器
  • 生成器对象,是延迟计算、惰性求值的
    生成器函数
  • 函数体中包含yield语句的函数,就是生成器函数,调用后返回生成器对象
    在这里插入图片描述
    生成器的执行
    普通函数调用,函数会立即执行直到执行完毕。
    生成器函数调用,并不会立即执行函数体,而是需要使用next函数来驱动生成器函数执行后获得的生成器对象。
    生成器表达式和生成器函数都可以得到生成器对象,只不过生成器函数可以写的更加复杂的逻辑。
    在这里插入图片描述
  • 在生成器函数中,可以多次yield,每执行一次yield后会暂停执行,把yield表达式的值返回
  • 再次执行会执行到下一个yield语句又会暂停执行
  • return语句依然可以终止函数运行,但return语句的返回值不能被获取到
  • return会导致当前函数返回,无法继续执行,也无法继续获取下一个值,抛出StopIteration异常
  • 如果函数没有显式的return语句,如果生成器函数执行到结尾(相当于执行了return None),一样会抛出
    StopIteration异常
    生成器函数
  • 包含yield语句的生成器函数调用后,生成 生成器对象 的时候,生成器函数的函数体不会立即执行
  • next(generator) 会从函数的当前位置向后执行到之后碰到的第一个yield语句,会弹出值,并暂停函数执行
  • 再次调用next函数,和上一条一样的处理过程
  • 继续调用next函数,生成器函数如果结束执行了(显式或隐式调用了return语句),会抛出StopIteration异

    生成器应用
    1、无限循环
    def counter():
    i = 0
    while True:
    i += 1
    yield i
    c = counter()
    print(next©) # 打印什么
    print(next©) # 打印什么
    print(next©) # 打印什么
    2、计数器
    def inc():
    def counter():
    i = 0
    while True:
    i += 1
    yield i
    c = counter()
    return next©
    print(inc()) # 打印什么?
    print(inc()) # 打印什么?
    print(inc()) # 打印什么?如何修改

修改上例
def inc():
def counter():
i = 0
while True:
i += 0
yield i
c = counter()
def inner():
return next©
return inner # returnn lambda : next©
foo = inc()
print(foo()) # 打印什么?
print(foo()) # 打印什么?
print(foo()) # 打印什么?为什么?
3、斐波那契数列
def fib():
x = 0
y = 1
while True:
yield y
x, y = y, x + y
foo = fib()
for i in range(101):
print(next(foo))
4 、生成器交互
python提供了一个和生成器对象交互的方法send,该方法可以和生成器沟通。
在这里插入图片描述

  • 调用send方法,就可以把send的实参传给yield语句做结果,这个结果可以在等式右边被赋值给其它变量
  • send和next一样可以推动生成器启动并执行。
    5、协程Coroutine
  • 生成器的高级用法
  • 它比进程、线程轻量级,是在用户空间调度函数的一种实现
  • Python3 asyncio就是协程实现,已经加入到标准库
  • Python3.5 使用async、await关键字直接原生支持协程
  • 协程调度器实现思路
    有2个生成器A、B
    next(A)后,A执行到了yield语句暂停,然后去执行next(B),B执行到yield语句也暂停,然后再次调用
    next(A),再调用next(B)在,周而复始,就实现了调度的效果
    可以引入调度的策略来实现切换的方式
  • 协程是一种非抢占式调度
    yield from语法
    从Python 3.3开始增加了yield from语法,使得 yield from iterable 等价于 for item in iterable: yield
    item 。
    yield from就是一种简化语法的语法糖。

在这里插入图片描述
本质上yield from的意思就是,从from后面的可迭代对象中拿元素一个个yield出去。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值