首页 > 编程知识 正文

python yield函数,python字符串格式化

时间:2023-05-05 23:43:13 阅读:111157 作者:759

2对yield和生成器的理解说明在Python中,使用yield的函数被称为生成器函数(generator function )。 生成器有两种方法: next (和send )。 它们都可以调用生成器yield VS return return直接返回所有结果,程序将退出并不再运行,局部变量将被丢弃。 yield生成断点、暂停函数和暂停函数,并保存当前状态。 然后,返回yield处的值,返回后,程序将不再继续执行。 yield和return用于函数中,负责返回某些结果。 具有yield的函数返回一个可重复生成器generator对象。 可以使用for循环,或者next (调用方法,send )方法可以遍历此生成的实例化生成器对象以提取结果。 2 yield生成器、next (,send )和方法生成器函数返回生成器对象。 对于生成器对象,python提供了两种主要方法: next )和send )。

2.1 next ) )函数是第一次对生成器对象调用next ) ),相当于启动生成器。 从生成器函数的第一行代码开始执行,在首次执行yield语句后一直持续到退出生成器函数。

然后,调用next (),进入生成器函数后,从yield语句的下一个语句开始执行,再执行到yield语句,执行后退出生成器函数。 稍后再次调用next (),以此类推。 也就是说,next ) )执行一次时,将调用一次生成器函数,直到抛出不可重复的错误。

def fun _ yield (:打印(startingfunyield ) ) while true : res=yield 4打印)确定是否在yield之后继续)、RES ) g=fun 生成器print (函数的结果为生成器),g ) print ) )也用于此生成器)、print )、print )、print )、print )生成器的返回值)、neer

在程序开始运行后,由于fun_yield具有yield关键字,因此函数并不实际执行,而是先得到实例化生成器对象,然后从结果1中可以看到实际上并不执行。 在调用next ()之前,fun_yield将正式开始执行,首先执行函数的打印(startingfunyield ) ),然后进入while循环。 在结果2中,您可以看到程序遇到了yield关键字,将yield理解为return,return。您没有执行下一个print (确定是否在' yield之后执行)或res (返回)操作。 此时,next ) g )语句已执行完毕,准备执行输出的前两行,然后是第二次调用。 在结果3中,您可以看到您正在运行以下print ),next ) ) g )。 此时与上述相同。 此时,将从上次yield停止的断点开始执行。 也就是说,执行print (确定是否在' yield之后执行)、res )操作。 此时,请注意赋值操作的右侧没有值()。因为刚才那个是return出去了,所以没有在赋值操作的左侧传递参数。 也就是说,res没有内容)。 因此,此时res赋值为None,所以接在下一个输出之后的是None。 结果4显示,后续程序将继续在while中运行,并再次碰撞yield。 此时也同样,return给出4,结果5为说明:

了解yield、return和generator之间的关系和差异:带yield的函数是生成器函数,直接使用并不实际执行,而是返回实例化的生成器对象。 在每次通过generator反复后,从yield返回的数据python提供生成器的方法next(next ) )相当于在"下一步骤"生成哪个数,此次的next ) )开始的地方在上次的yield之后next ) )时,生成器不是从头开始执行函数,而是在上次停止的位置之后开始,如果遇到yield,则返回表达式,此步骤结束。 2.2 send (函数send ) (函数和next ) (函数其实很相似。 唯一的区别是send ) )函数可以传递值,但next ) )函数不能传递值。 可以这样说。

第一次调用next(f )=f.send (None ) )时,不能使用send )发送非none值。 否则,将出现错误,因为没有接收此值的yield语句。

举个例子:

def fun _ yield (:打印(startingfunyield ) ) while true : res=yield 4打印)确定是否在yield之后继续)、RES ) g=fun 生成器print ('函数的结果是生成器(,g ) print ) )是调用该生成器,还是调用)、print )、print )、print )、next )、g ) )

))print("第三次调用")print("生成器的返回值",g.send(3))

主要变化:

之前res的值是None,现在变成1,2,3,因为send是发送参数给res,因为上面讲到,return的时候,并没有把4赋值给res,下次执行的时候只好继续执行赋值操作,只好赋值为None了。

如果用send的话,出现的情况是,先接着上一次(yield 4之后)执行,先把接受到的1,2,3等赋值给了res,然后执行打印的作用,程序执行再次遇到yield关键字,yield会返回后面的值后,程序再次暂停,直到再次调用next()方法或send()方法。

注意:

生成器在迭代的过程中可以改变当前迭代值,而修改普通迭代器的当前迭代值往往会发生异常,影响程序的执行。(因为生成器有send()方法)

def myList(num): # 定义生成器 now = 0 # 当前迭代值,初始为0 while now < num: val = (yield now) # 返回当前迭代值,并接受可能的send发送值; now = now + 1 if val is None else val # val为None,迭代值自增1,否则重新设定当前迭代值为val my_list = myList(5) # 得到一个生成器对象print my_list.next() # 返回当前迭代值print my_list.next()my_list.send(3) # 重新设定当前的迭代值print my_list.next()

3 常用的代码例子 3.1 例子1 输出斐波那契数列的前N个数(比较常用的使用方式)

调用fab(5)不会执行fab函数,而是返回一个generator对象。在for循环执行时,每次循环都会执行fab函数内部的代码,执行到yield b时,fab函数就返回一个迭代值,下次迭代时,代码从yield b的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到yield。

def fab(max): n, a, b = 0, 0, 1 while n < max: yield b # 使用 yield a, b = b, a + b n = n + 1for n in fab(5): print(n,end = " ") f = fab(5)print(next(f))print(next(f))print(next(f))print(next(f))print(next(f))print(next(f))

3.2 例子2 使用types和inspect库判断是否为生成器或生成器函数(关于类型判断的说明) def fab(max): n, a, b = 0, 0, 1 while n < max: yield b # 使用 yield a, b = b, a + b n = n + 1from inspect import isgeneratorfunctionprint(isgeneratorfunction(fab))print(isgeneratorfunction(fab(5)))import types print(isinstance(fab, types.GeneratorType) )print(isinstance(fab(5), types.GeneratorType))

要注意区分fab和fab(5)

fab是一个generator function,而fab(5)是调用generator function返回的一个generator,好比类的定义和类的实例的区别,fab是无法迭代的,而fab(5)是可迭代的。

3.3 例子3 多个生成器不影响

每次调用含有yield的函数行成一个新的generator实例,各实例互不影响。

def fab(max): n, a, b = 0, 0, 1 while n < max: yield b # 使用 yield a, b = b, a + b n = n + 1from inspect import isgeneratorfunctionf1 = fab(3) f2 = fab(5) print("f1:",next(f1))print("f2:",next(f2))print("f1:",next(f1))print("f2:",next(f2))print("f1:",next(f1))print("f2:",next(f2))print("f2:",next(f2))print("f2:",next(f2))

3.4 例子4 文件读取

如果直接对文件对象调用read()方法,会导致不可预测的内存占用。好的方法是利用固定长度的缓冲区来不断读取文件内容。通过yield,不再需要编写读文件的迭代类,就可以轻松实现文件读取:

def read_file(fpath): BLOCK_SIZE = 1024 with open(fpath, 'rb') as f: while True: block = f.read(BLOCK_SIZE) if block: yield block else: return 4 yield 优势

Python 2 中的一个特性:内建函数 range 和 xrange。其中,range 函数返回的是一个列表,而 xrange 返回的是一个迭代器。在 Python 3 中,range 相当于 Python 2 中的 xrange;而 Python 2 中的 range 可以用 list(range()) 来实现。

Python做出如下的优化主要原因就是:如果用List的话,会占用更大的空间。这个时候在python2中range(1000)就默认生成一个含有1000个数的list了,所以很占内存。

for n in range(1000): a=n

这个时候可以用yield组合成生成器实现

def foo(num): print("starting...") while num<10: num=num+1 yield numfor n in foo(0): print(n,end=" ")

之所以要提供这样的解决方案,是因为在很多时候,只是需要逐个顺序访问容器内的元素。大多数时候,不需要一口气获取容器内所有的元素。比方说,顺序访问容器内的前 5 个元素,可以有两种做法:

获取容器内的所有元素,然后取出前 5 个;从头开始,逐个迭代容器内的元素,迭代 5 个元素之后停止。

显而易见,如果容器内的元素数量非常多(比如有 10 ** 8 个),或者容器内的元素体积非常大,那么后一种方案能节省巨大的时间、空间开销。

现在假设,有一个函数,其产出(返回值)是一个列表。而若知道,调用者对该函数的返回值,只有逐个迭代这一种方式。那么,如果函数生产列表中的每一个元素都需要耗费非常多的时间,或者生成所有元素需要等待很长时间,则使用 yield 把函数变成一个生成器函数,每次只产生一个元素,就能节省很多开销了。

LAST 参考文献

python中yield的用法详解——最简单,最清晰的解释_mieleizhi0522的博客-CSDN博客_yield

Python yield 使用浅析 | 菜鸟教程

如何理解Python中的yield用法? - 知乎

python的yield和yield from - 华为云

Python 中的黑暗角落(一):理解 yield 关键字 | 始终

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。