Self-study Python Fish-C Note13 P48to49

函数 (part 3)

本节主要讲函数的 lambda 表达式, 生成器

lambda 表达式 (匿名函数)(P48)

匿名函数(lambda 表达式)语法规则:lambda arg1, arg2, arg3, ... argN : expression

其中 arg 为参数,expression 为函数实现的表达式以及返回值

我们把lambda表达式作为极致精简的函数,相当于传统函数定义的:
def <lambda> (arg1,arg2,arg3,... argN): return expression

示例 1:

python 复制代码
# 传统定义的函数
def squareX(x):
    return x*x
squareX(3)
复制代码
9
python 复制代码
# lambda 表达式
squareY = lambda y : y*y
squareY(3)
复制代码
9
python 复制代码
# 传统定义的函数函数名就是一个函数的引用
squareX
复制代码
<function __main__.squareX(x)>
python 复制代码
# 而 lambda 表达式,整个表达式就是一个函数的引用
squareY
复制代码
<function __main__.<lambda>(y)>

两者重大的区别就是,lambda 是一个表达式,可以用在常规函数不可能存在的地方。

示例2:lambda 表达放入列表(这里只是做示例示范可以,但不推荐大家开发的时候这么写哈)

python 复制代码
y = [lambda x:x*x,2,3]
y[0](y[1]) # 把 y 列表的第二个值(2),传入列表第一个值 lambda 表达式中
复制代码
4

lambda 表达式与 mapfilter 等函数合用。这两者的参数都是要求传入一个用于计算的函数,此时就可以使用 lambda 表达式。

比如 map 函数,第一个参数就是传入一个函数的引用,第二个参数要求是序列类型,其会把每个元素挨个传递给第一个参数指定的函数,在运算之后把结果构成一个迭代器返回。

示例3:

python 复制代码
mapped = map(lambda x:ord(x)+10, 'abcdef')
list(mapped)
复制代码
[107, 108, 109, 110, 111, 112]
python 复制代码
# 如果我们用传统的函数
def tradation(x):
    return ord(x)+10
list(map(tradation,'abcdef'))
复制代码
[107, 108, 109, 110, 111, 112]
python 复制代码
# 再比如我们用在 filter 上
list(filter(lambda x : x%2,range(10))) # 求 10 以内的所有奇数
复制代码
[1, 3, 5, 7, 9]

总结,lambda 是一个表达式而非语句,所以它能够出现在 Python 语法不允许 def 语句出现的地方(优势)。但由于所有的功能代码都局限在一个表达式中实现,因此 lambda 通常也只能实现那些较为简单的需求。一般来讲,匿名函数用于实现简单的需求,def 语句负责用于定义功能复杂的函数,去处理复杂的工作。

生成器 (generator) (P49)

对于调用一个普通的 Python 函数来说,一般我们都是从函数的第一行代码开始执行的,当所有语句执行完毕,或者遇到 return 语句的时候,这个函数就算是结束了。一旦函数将控制权交还给调用者的时候,这就意味这这个函数的结束。函数中做的所有工作,以及保存在局部变量中的数据也都会丢失。当再次调用的时候,一切从头开始。

有没有办法让函数在退出之后还能保留状态呢?使用闭包或者全局变量。不过过多使用全局变量会污染命名空间,闭包的定义又相对复杂。

此时,生成器 (generator) 就是一个更简单和安全的方法。

定义一个生成器:

在函数中使用 yield 表达式来代替 return语句

示例1:

python 复制代码
def counter():
    i=0
    while i <= 3:
        yield i
        i+=1
# 这样我们就定义了一个 叫 counter 的生成器
# 现在我们调用 counter() 函数
counter() # 可以看到得到的不再是一个返回值,而是一个生成器对象 `generator object`
复制代码
<generator object counter at 0x0000017F4A3B8430>
python 复制代码
# counter 现在是一个生成器了,我们可以在 for 中使用
for i in counter():
    print(i)
复制代码
0
1
2
3

我们知道 for 语句,是从一个可迭代对象里面每次获取一个数据。这个 counter 生成器的作用就是每次调用的时候提供一个数据,注意是提供一个数据。

更深入讲,每次在执行到 yield i的时候,就生成一个数据,暂停并保留状态。下一次调用则从下一个语句 i+=1开始继续执行。

注意:生成器它不像是列表,元组之类的可迭代对象,生成器可以看作是一个制作机器,他的作用就是每调用一次提供一个数据,并且会记住当时的状态。而列表元组这些可迭代对象则是容器,他们里面存放的是早已经准备好的所有数据。生成器是一种特殊的迭代器,他首先不走回头路,其次支持 next()函数

python 复制代码
c = counter()
next(c)
复制代码
0
python 复制代码
next(c)
复制代码
1
python 复制代码
next(c)
复制代码
2
python 复制代码
next(c)
# 如果再 使用 next(c) 就会抛出 StopIteration 的异常
复制代码
3

由于生成器每调用一次获取一个结果的特性,所以生成器对象是无法使用下标索引这种随机访问的方式的

python 复制代码
c = counter()
print(next(c))
print(next(c)) # 此时 c 的状态 i =1
print('_'*30)
for i in c: # 再调用是从 i=1开始 i=i+1
    print(i)
复制代码
0
1
______________________________
2
3

示例2:

使用生成器来实现 斐波那契数列

斐波那契数列:由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出:0,1,1,2,3,5,8 ...

python 复制代码
def fib():
    back1,back2 = 0,1
    while True:
        yield back1
        back1,back2 = back2,back1+back2
        
f = fib()
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
复制代码
0
1
1
2
3
5
8
13

这里我们写了一个无限的斐波那契数列,如果我们不小心用到了 for 上,他就会一直生成下去。此时要用 control+C 强制退出,否则会一直进行下去

生成器表达式 (generator expression)

在之前的课程中我们提到过,列表有列表推导是而元组则没有。这里就可以做一个解答,列表推导式的 [] 换成 (),其实就变成了生成器表达式。

示例:

python 复制代码
(i**2 for i in range(3))
复制代码
<generator object <genexpr> at 0x0000017F4A3C49E0>
python 复制代码
t = (i**2 for i in range(3)) # range(3) 包括 0,1,2 不包括 3
print(next(t))
print(next(t))
print(next(t))
复制代码
0
1
4

这种利用推导的形式获得生成器的方法,我们称之为生成器表达式。生成器表达式和列表推导式最大的不同就是,列表推导式会一下子将所有数据生产出来并放到一个列表中,但是生成器表达式一次只生成一个数据。
总结来说,生成生成器的两种方法一个就是使用 yield 表达式,另一个就是直接使用生成器表达式。

附言: 题目:Self-study Python Fish-C Note-13 P48-P49 本文为自学B站上鱼C的python课程随手做的笔记。一些概念和例子我个人为更好的理解做了些查询和补充 因本人水平有限,如有任何问题,欢迎大家批评指正! 原视频链接:https://www.bilibili.com/video/BV1c4411e77t?p=8

相关推荐
汤姆_51114 分钟前
【c语言】深入理解指针1
c语言·开发语言
人猿泰飞17 分钟前
在Ubuntu-22.04.5中安装ONLYOFFICE DocSpace(协作空间)【注意:安装失败,谨慎参考!】
java·linux·运维·python·ubuntu·项目管理·onlyoffice
gospace20 分钟前
Golang Event Bus 最佳实践:使用 NSQite 实现松耦合架构
开发语言·架构·golang·事件·总线·event·event bus
Enougme23 分钟前
python-将文本生成音频
python·音视频·语音识别
风中飘爻26 分钟前
JavaScript:表单及正则表达式验证
开发语言·javascript·ecmascript
极客先躯1 小时前
高级java每日一道面试题-2025年4月07日-微服务篇[Nacos篇]-如何监控Nacos的运行状态?
java·开发语言·微服务
拖拉机1 小时前
Python(八)类(下)
后端·python
牛了爷爷1 小时前
php伪协议
android·开发语言·php
CSUC1 小时前
【开发语言】悬空指针问题
开发语言
晓13131 小时前
第三章 爬虫提速、selenium模块、requests模块进阶(终)
爬虫·python·selenium·测试工具·http