python中的推导式、生成器(二)

简介: python中的推导式、生成器(二)

python中的推导式、生成器(一):https://developer.aliyun.com/article/1495750


五, 生成器函数

#yield 类似于 return

共同点在于:执行到这句话都会把值返回出去

不同点在于:yield每次返回时,会记住上次离开时执行的位置 , 下次在调用生成器 , 会从上次执行的位置往下走

而return直接终止函数,每次重头调用.

yield 6 和 yield(6) 2种写法都可以 yield 6 更像 return 6 的写法 推荐使用

携程之所以能在不同任务里面切换,依赖的就是yield,能记住这次任务中执行的位置和状态,CPU切换时从上次位置往下走


“”"

#(1) 基本语法

def mygen():
    print("111")
    yield 1
    
    print("222")
    yield 2
    
    print("333")
    yield 3

#初始化生成器函数 => 返回生成器对象 => 简称生成器

调用该函数的时候不会立即执行代码,而是返回了一个生成器对象;

当使用 next() (在 for 循环中会自动调用 next() ) 作用于返回的生成器对象时,函数 开始执行,在遇到 yield 的时候会『暂停』,并返回当前的迭代值;

当再次使用 next() 的时候,函数会从原来『暂停』的地方继续执行,直到遇到 yield语句,如果没有 yield 语句,则抛出异常;

# 第一次调用
res = next(gen)
print(res)
# 第二次调用
res = next(gen)
print(res)
# 第三次调用
res = next(gen)
print(res)
# 第四次调用

StopIteration error 
res = next(gen)
print(res)

创建生成器方法:

(1)生成器表达式 (里面是推导式,外面用圆括号)

(2)生成器函数 (用def定义,里面含有yield)

调用方法:

1.使用生成器对象的实例方法 生成器.next()

2.使用Python内置方法 next(生成器)

# 第一次调用
print("111")  yield 1 保存当前第13行代码的状态,把1返回,并且等待下一次调用
# 第二次调用
从上一次保存的位置13行往下走, print("222") yield 2 保存当前第16行代码的状态,把2返回,并且等待下一次调用
# 第三次调用
从上一次保存的位置16行往下走, print("333") yield 3 保存当前第19行代码的状态,把3返回,并且等待下一次调用
# 第四次调用
因为没有更多的yield 返回数据,所有停止迭代.出现报错异常.

#(2) 优化生成器代码

“”“生成器应用的场景是在大数据的范围中使用, 切记不可直接用for遍历所有,可能无法短时间内获取所有数据”“”

每次手动写yield 1…2…3…4…就太蠢了,需要优化

def mygen():
    for i in range(1,101):
        yield i

#初始化生成器函数 => 生成器
gen = mygen()
print("<=====>")
for i in range(30):
    num = next(gen)
    print("我的球衣号码是{}".format(num))

print("<=====>")

可以连续遍历:,号码从上次遍历结尾接着开始

for i in range(40):

num = next(gen)

print(“我的球衣号码是{}”.format(num))

#(3) send的使用方式 (给上一个yield发送数据)

#next和send区别:

next 只能取值

send 不但能取值,还能发送值,发送给yield

#send注意点:

第一个 send 不能给 yield 传值 默认只能写None

最后一个yield 接受不到send的发送值

def mygen():
    print("start")
    
    res = yield "内部1"
    print(res,"<==内部==>")
    
    res = yield "内部2"
    print(res,"<==内部==>")
    
    res = yield "内部3"
    print(res,"<==内部==>")
    
    print("end")
    
# 初始化生成器函数 => 生成器
gen = mygen()
# 第一次调用生成器
"""
第一次调用生成器时,因为没有遇到yield保存的代码位置,
无法发送数据,默认第一次只能发送None
"""
res = gen.send(None)
print(res,"<==外部==>")

# 第二次调用生成器
res = gen.send("100")
print(res,"<==外部==>")

# 第三次调用生成器
res = gen.send("200")
print(res,"<==外部==>")

# 第四次调用生成器
"""
error
res = gen.send("300")
print(res,"<==外部==>")
"""
"""
使用send调用生成器,第一次发送时必须是None,因为还没有遇到yield保存的代码位置
res = gen.send(None)  走到mygen生成器函数中
print("start") 
res = yield "内部1"  执行第80行 ,保存退出,记录当前代码位置,将 "内部1" 返回
在98行接受数据  res = "内部1"  print(内部1,"<==外部==>")

第二次调用生成器
res = gen.send("100") 把100这个数据发送给上一次代码保存的位置80行进行接受. => 导致 80行 res = 100
打印81行  print(100 ,"<==内部==>")
执行83行  res = yield "内部2"  保存退出,记录当前代码位置,将 "内部2" 返回
执行102行 res = gen.send("100") => "内部2" print("内部2","<==外部==>")

依次类推 …

到第四次调用时, 因为没有更多的yield 返回数据,gen.send(300)无法接受到返回值,所以出现停止迭代 StopIteration的报错,程序终止;

send执行流程

send要想成功执行,第一次必须发送None,最后一次调用,要有对应层级的yield,也就是send个数少于等于yield个数

#(4) yield from 的使用

“”“将一个可迭代对象变成一个迭代器返回 “””

def mygen():
    lst = ["张磊","李亚峰","刘一峰","王同培"]
    yield from lst
    
#初始化生成器函数
gen = mygen()
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
#print(next(gen)) # StopIteration

#(5) 斐波那契数列

使用生成器分段获取所有内容,而不是一股脑的把所有数据全部打印

1 1 2 3 5 8 13 21 34 …

def mygen(maxval):
    a,b = 0,1
    i = 0
    while i < maxval:
        # print(b) 
        yield b
        a,b = b,a+b
        i += 1
# mygen(10)
gen = mygen(10)

# 第一次获取
for i in range(3):
    print(next(gen))

# 第二次获取
for i in range(5):
    print(next(gen))

使用生成器,可以分段获取,不用全部打印


相关文章
|
15天前
|
存储 索引 Python
|
13天前
|
Python
探索Python中的列表推导式
【10月更文挑战第20天】在编程世界里,时间就是一切。Python的列表推导式是节约时间、简化代码的一大利器。本文将带你深入理解并有效利用这一强大工具,从基础到高级用法,让你的代码更加简洁高效。
|
11天前
|
弹性计算 安全 数据处理
Python高手秘籍:列表推导式与Lambda函数的高效应用
列表推导式和Lambda函数是Python中强大的工具。列表推导式允许在一行代码中生成新列表,而Lambda函数则是用于简单操作的匿名函数。通过示例展示了如何使用这些工具进行数据处理和功能实现,包括生成偶数平方、展平二维列表、按长度排序单词等。这些工具在Python编程中具有高度的灵活性和实用性。
|
12天前
|
C语言 开发者 Python
探索Python中的列表推导式:简洁而强大的工具
【10月更文挑战第21天】在Python的世界里,代码的优雅与效率同样重要。列表推导式(List Comprehensions)作为一种强大而简洁的工具,允许开发者通过一行代码完成对列表的复杂操作。本文将深入探讨列表推导式的使用方法、性能考量以及它如何提升代码的可读性和效率。
|
16天前
|
Python
Python生成器、装饰器、异常
【10月更文挑战第15天】
|
18天前
|
数据处理 开发者 Python
Python中的列表推导式:一种优雅的代码简化技巧####
【10月更文挑战第15天】 本文将深入浅出地探讨Python中列表推导式的使用,这是一种强大且简洁的语法结构,用于从现有列表生成新列表。通过具体示例和对比传统循环方法,我们将揭示列表推导式如何提高代码的可读性和执行效率,同时保持语言的简洁性。无论你是Python初学者还是有经验的开发者,掌握这一技能都将使你的编程之旅更加顺畅。 ####
19 1
|
5天前
|
存储 程序员 数据处理
深入理解Python中的生成器与迭代器###
本文将探讨Python中生成器与迭代器的核心概念,通过对比分析二者的异同,结合具体代码示例,揭示它们在提高程序效率、优化内存使用方面的独特优势。生成器作为迭代器的一种特殊形式,其惰性求值的特性使其在处理大数据流时表现尤为出色。掌握生成器与迭代器的灵活运用,对于提升Python编程技能及解决复杂问题具有重要意义。 ###
|
10天前
|
C语言 Python
探索Python中的列表推导式:简洁而强大的工具
【10月更文挑战第24天】在Python编程的世界中,追求代码的简洁性和可读性是永恒的主题。列表推导式(List Comprehensions)作为Python语言的一个特色功能,提供了一种优雅且高效的方法来创建和处理列表。本文将深入探讨列表推导式的使用场景、语法结构以及如何通过它简化日常编程任务。
|
25天前
|
存储 大数据 数据处理
理解Python中的生成器:高效迭代的秘密
【10月更文挑战第8天】理解Python中的生成器:高效迭代的秘密
28 0
|
25天前
|
存储 大数据 程序员
深入理解Python中的生成器
【10月更文挑战第8天】深入理解Python中的生成器
10 0