
正文
Python生成器函数 python生成器函数yield
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
Python 函数 - 返回生成器
如果函数要返回一系列结果,我们常见的方法就是将结果放到一份列表中,然后返回给调用者。比如下面的函数,返回字符串中每个单词的首字母在真个字符串中的索引:
运行结果:
上述的结果完全符合我们的预期,但 get_word_index 函数不够简洁。下面我们尝试使用生成器来实现:
运行结果:
改写之后,不仅运行结果符合要求,由于不需要和 result 列表交互,函数也变得非常简洁。下面我们就来详细学习下生成器吧~
生成器是指使用 yield 表达式的函数,调用生成器函数时,它并不会真的运行,而是会返回迭代器。每次在这个迭代器上面调用内置的 next 函数时,迭代器就会把生成器推进到下一个 yield 表达式那里。生成器传给 yield 的值均会由迭代器返回给调用者。
此外,如果输入量非常大,使用列表作为返回值,那么程序就有可能耗尽内存并崩溃。相反,使用生成器之后,则可以应对任意长度的输入数据。
例如,下面这个生成器函数可以获取文件中单词的索引,而不管文件内容多大,该函数执行时消耗的内存,只由单行的文本长度决定:
其中 test_generator.txt 中的内容如下:
运行结果:
下面这句话特别重要: 生成器函数返回的迭代器,是由状态的,及调用者不应该反复使用它 。我们那 word_index_iter 来说明:
如果想重复调用,请将其封装成容器:
运行结果:
关于上述自定义容器的实现原理,我的另外一篇文章做了详细介绍,链接奉上:
相关问答
Q1: python生成10个账号
1、列表解析(数据量少)
[i for i in range(10)]
2、生成器(可迭代对象)表达式(数据量大)
生成器自动是实现迭代器协议(next方法)Python生成器函数,用next取值后,该值不会再产生了,省内存。
( i for i in range(10) )
2、生成器函数
yieldPython生成器函数:yield 1 相当于return返回值,但可以执行多次Python生成器函数;x=yield保留函数运行状态; 接受send 传过来的值复制给x,若没有send返回none。
send可以使生成器接着运行(有点像next),generator.send(none):send把none传给yield,进行触发。
def test():
yield 1
yield 2
yield 3
response=test() #拿到生成器,response为生成器对象。
执行:print( response.__next__() )
3、生成器函数深入
例1
(1)、def product_baozi():
re=[ ]
for i in range(10):
re.append("baozi%s" %i)
return re
(2)def product_baozi():
for i in range(10): #循环生成列表
yield "baozi%s" %i
pro_g=product_baozi() #生成器对象
#取值
for i in pro_g:
print(i)
或者:baozi=pro_g.__next__() #一个一个取值
注意:(2)的效率比(1)高,省内存,保留函数运行状态(状态挂起);生成器只能遍历一次
例2
def get_population():
with open ("人口普查",“r”encoding=‘utf-8’) as f:
yield i
data=get_population() #可迭代对象,只能迭代一次
#求和
ret=0
for p in data: #相当与data.__next__() (next(t))
p_dict=eval(p) #转成字典
ret+=p_dict[ 'population ' ]
或者:all_population=sum(eval(i)['population'] for i in data) #sum(可迭代对象)
#比例
for i in data: #注意data中的值被使用完了
rate= eval(i)['population'] / all_population
注意:evel:把字符串里面的数据类型提取出来,字符串里面的表达式运算出来
Q2: python生成器多次遍历(一)------复制生成器
当python中Python生成器函数的生成器被完整遍历一次后Python生成器函数,就无法再次遍历。
Python生成器函数我们希望享有生成器迭代占用内存小的特性,又希望这个生成器能被遍历多次。
方案之一是使用函数 itertools.tee 来复制生成器
语法: generator1, generator2 = itertools.tee(generator, n=2)
generator是需要复制的生成器, n是复制出生成器个数,默认为2。
我们为Python生成器函数了生成器能多次遍历,可以这样写:
generator, copy_generator = itertools.tee(generator, 2)
然后遍历copy_generator,保存的generator可以再次复制。
1、generator被复制后尽量不要使用
2、如果生成器中迭代的还是生成器,复制最外层生成器,生成器依然只能遍历一次。
下一篇
python生成器多次遍历(二)------创建生成器类
Q3: Python中的“迭代”详解
迭代器模式:一种惰性获取数据项的方式,即按需一次获取一个数据项。
所有序列都是可以迭代的。我们接下来要实现一个 Sentence(句子)类,我们向这个类的构造方法传入包含一些文本的字符串,然后可以逐个单词迭代。
接下来测试 Sentence 实例能否迭代
序列可以迭代的原因:
iter()
解释器需要迭代对象 x 时,会自动调用iter(x)。
内置的 iter 函数有以下作用:
由于序列都实现了 __getitem__ 方法,所以都可以迭代。
可迭代对象:使用内置函数 iter() 可以获取迭代器的对象。
与迭代器的关系:Python 从可迭代对象中获取迭代器。
下面用for循环迭代一个字符串,这里字符串 'abc' 是可迭代的对象,用 for 循环迭代时是有生成器,只是 Python 隐藏了。
如果没有 for 语句,使用 while 循环模拟,要写成下面这样:
Python 内部会处理 for 循环和其他迭代上下文(如列表推导,元组拆包等等)中的 StopIteration 异常。
标准的迭代器接口有两个方法:
__next__ :返回下一个可用的元素,如果没有元素了,抛出 StopIteration 异常。
__iter__ :返回 self,以便在需要使用可迭代对象的地方使用迭代器,如 for 循环中。
迭代器:实现了无参数的 __next__ 方法,返回序列中的下一个元素;如果没有元素了,那么抛出 StopIteration 异常。Python 中的迭代器还实现了 __iter__ 方法,因此迭代器也可以迭代。
接下来使用迭代器模式实现 Sentence 类:
注意, 不要 在 Sentence 类中实现 __next__ 方法,让 Sentence 实例既是可迭代对象,也是自身的迭代器。
为了“支持多种遍历”,必须能从同一个可迭代的实例中获取多个独立的迭代器,而且各个迭代器要能维护自身的内部状态,因此这一模式正确的实现方式是,每次调用 iter(my_iterable) 都新建一个独立的迭代器。
所以总结下来就是:
实现相同功能,但却符合 Python 习惯的方式是,用生成器函数代替 SentenceIteror 类。
只要 Python 函数的定义体中有 yield 关键字,该函数就是生成器函数。调用生成器函数,就会返回一个生成器对象。
生成器函数会创建一个生成器对象,包装生成器函数的定义体,把生成器传给 next(...) 函数时,生成器函数会向前,执行函数定义体中的下一个 yield 语句,返回产出的值,并在函数定义体的当前位置暂停,。最终,函数的定义体返回时,外层的生成器对象会抛出 StopIteration 异常,这一点与迭代器协议一致。
如今这一版 Sentence 类相较之前简短多了,但是还不够慵懒。 惰性 ,是如今人们认为最好的特质。惰性实现是指尽可能延后生成值,这样做能节省内存,或许还能避免做无用的处理。
目前实现的几版 Sentence 类都不具有惰性,因为 __init__ 方法急迫的构建好了文本中的单词列表,然后将其绑定到 self.words 属性上。这样就得处理整个文本,列表使用的内存量可能与文本本身一样多(或许更多,取决于文本中有多少非单词字符)。
re.finditer 函数是 re.findall 函数的惰性版本,返回的是一个生成器,按需生成 re.MatchObject 实例。我们可以使用这个函数来让 Sentence 类变得懒惰,即只在需要时才生成下一个单词。
标准库提供了很多生成器函数,有用于逐行迭代纯文本文件的对象,还有出色的 os.walk 函数等等。本节专注于通用的函数:参数为任意的可迭代对象,返回值是生成器,用于生成选中的、计算出的和重新排列的元素。
第一组是用于 过滤 的生成器函数:从输入的可迭代对象中产出元素的子集,而且不修改元素本身。这种函数大多数都接受一个断言参数(predicate),这个参数是个 布尔函数 ,有一个参数,会应用到输入中的每个元素上,用于判断元素是否包含在输出中。
以下为这些函数的演示:
第二组是用于映射的生成器函数:在输入的单个/多个可迭代对象中的各个元素上做计算,然后返回结果。
以下为这些函数的用法:
第三组是用于合并的生成器函数,这些函数都可以从输入的多个可迭代对象中产出元素。
以下为演示:
第四组是从一个元素中产出多个值,扩展输入的可迭代对象。
以下为演示:
第五组生成器函数用于产出输入的可迭代对象中的全部元素,不过会以某种方式重新排列。
下面的函数都接受一个可迭代的对象,然后返回单个结果,这种函数叫“归约函数”,“合拢函数”或“累加函数”,其实,这些内置函数都可以用 functools.reduce 函数实现,但内置更加方便,而且还有一些优点。
参考教程:
《流畅的python》 P330 - 363
Q4: Python生成器简介
Python 中的 yield 关键字鲜为人知,但是作用却很大,正是因为有Python生成器函数了yield,才有Python生成器函数了Python生成器。
yield 是 Python 的关键字,它用于 从函数返回而不破坏其局部变量的状态 ,并且在调用该函数时,从最后一个 yield 语句开始执行。任何包含 yield 关键字的函数都称为生成器。
Python 中的 yield 关键字的作用类似于 Python 中的 return 语句,不同之处在于:
yield的优点
yield的缺点
Python 可以使用 括号() 创建生成器
更多时候,我们使用 yield 关键字创建生成器
下面这个生成器,前4次调用它时,返回的是0-3这几个特殊值,第5次调用它时返回一个10-20之间的随机整数。
更多时候,生成器可以返回无限的值。
注意 generator() 函数返回的是一个生成器对象,要想获取它的值,可以像上面那样在迭代器中取出它的值,我们也可以显式的调用next函数获取值。
Python | yield Keyword - GeeksforGeeks:
Q5: python中randum.randum(10)是什么意思?
Python中random.random(10)Python生成器函数的意思是生成一个介于0和1之间的随机小数Python生成器函数,数字10是指随机数生成器的种子。random.random()函数是Python内置的随机数生成器函数,会生成一个0到1之间的随机小数,包括0,不包括1。如果参数不给定则使用系统当前时间(单位:秒)来作为种子随机数生成器。如果在生成随机数时使用相同的种子,则可以得到相同的随机数序列。
在本例中,数字10作为种子随机数生成器,是为Python生成器函数了使得随机数生成器生成的随机数序列每次运行程序时都是一样的。如果想要每次生成不同的随机数,可以在每次运行代码时不输入种子参数,或者输入一个随机的种子值来实现。
关于Python生成器函数和python生成器函数yield的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。






