Python中yield分析

48 篇文章 11 订阅
Neutron中的yield关键词进行协程的编程场景并不是很多,但是了解yield,对了解协程的基本概念和原理会有很大的帮助。Python中的yield与迭代器的概念相关,我们先从迭代器的概念说起:
一 迭代器
迭代器(iterator),严格地说是一个容器对象,根据迭代器协议(规则),它需要实现两个基本方法:
1 __iter__,返回迭代器自身(容器对象);
2 next,返回迭代器下一个元素(从Python 3开始,改为__next__)。
首先看一个例子:
class myiter(object):
        def __init__(self,count):
            self.count=count
        def __iter__(self):
            return self
        def __next__(self):
            if(0>=self.count):
                raise StopIteration()
            else:
                self.count -= 1
                return self.count
                
for e in myiter(4):
    print(e)
迭代器的用法很精练,不过这种精练不够直接
这段代码的输出结果是:
3
2
1
0
需要解释的是“for e in myiter(4)”,这一句话有三层含义:
1 myiter(4),构建一个myiter对象,传入参数值是4;
2 通过__iter__函数,返回一个迭代器;
3 通过__next__函数,一个元素一个元素顺序获取,直到元素获取结束(raise StopIteration())。
我们可以把for e in myiter(4)这句代码改写一下,看起来会更直接:
#构建一个myiter(4)对象it
myiter it = myiter(4)
#循环调用it的__next__函数
while 1:
        e=it.__next__()
        print(e)
通过上述代码,我们看到,一个class只要实现__iter__、__next__,这两个函数,就可以称为迭代器。
二 yield关键词
使用yeild关键进行编程,就涉及了迭代器的概念。先看下面这个例子:
def fy(count):
    c=count
    while c>0:
        c=c-1
        yield c
        
f=fy(4)
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())
上面的这个例子,让人感觉莫名其妙:fy表面上看起来是一个函数,f不过是一个函数对象而已,怎么会突然冒出一个成员函数__next__出来?
这一切都是因为fy中的一句yield c,原本仅仅是一个函数fy,由于yield的存在,变得完全不同。yield在这里起到的作用就是把一个普通的函数变成了一个生成器。所谓生成器,简单理解就是:迭代器+协程。也就是说yield有两重作用。
yield的第一重作用是把一个普通函数变成了一个迭代器。既然是迭代器,就得具有__next__函数,所以yield会给这个生成器加一个__next__函数,而这个__next__函数的具体实现,就相对于原来的函数体。我们先把fy函数变成一个迭代器,伪代码如下:
class fy_generator(object):
        def __init__(self,count):
            self.count=count
        def __iter__(self):
            return self
        def __next__(self):
            c=self.count
            while c>0:
                c=c-1
                yield c
这个迭代器的__next__函数中,仍然具有yield这个关键词,因为它已经把一个普通函数变成了一个迭代器,所以此时的yield将只会具有第二层作用,把__next__函数变成一个协程。yield的第二层作用,具体描述如下:
1 当__next__函数被调用,执行到yield时,首先相对于return c。
2 但是yield c又不是完全等价于return c,否则函数就退出了。所以,yield的第2个功能相对于保存了当时运行的上下文,把函数挂起。
3 既然把函数挂起,就相对于该协程让出程序执行权(让出上下文,由另外的协程来运行)。
4 当这个__next__函数再次被调用,它是从当初挂起的地方继续执行,直到再次执行yield c那句函数,然后又开始从第1点开始循环。
5 __next__函数可能这样一直循环下去,也可能在某种情况下没有执行到yield c,就函数退出了,那么此时__next__函数会抛出一个异常:raise StopIteration。
综上,关于yield两重作用的描述,重新解释一下所举的例子,如下表:
Neutron使用yield关键词编程,实际上还是属于用户(编程者/应用程序)自己对协程进行调度(函数挂起,让渡给别的函数执行)。
  • 10
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
yield函数是Python的一个关键字,用于定义生成器函数。生成器是一种特殊的迭代器,它可以通过yield语句来暂停和恢复函数的执行,从而实现按需生成数据的功能。 通过yield函数,我们可以将一个函数转化为生成器函数,函数包含yield语句的地方会被暂停执行,并返回一个值给调用者。当生成器函数再次被调用时,会从上次暂停的位置继续执行,直到再次遇到yield语句或函数结束。这种实现方式可以有效地节省内存,并提高性能。 下面以一个实例来详细说明yield函数的使用。 ``` def generate_numbers(n): i = 0 while i < n: yield i i += 1 numbers = generate_numbers(5) print(next(numbers)) # 输出:0 print(next(numbers)) # 输出:1 print(next(numbers)) # 输出:2 print(next(numbers)) # 输出:3 print(next(numbers)) # 输出:4 ``` 在这个例子,generate_numbers是一个生成器函数。当调用它时,它会返回一个生成器对象。我们通过调用next()函数来获取生成器对象的下一个值。每次调用next()函数时,函数会从yield语句处恢复执行,并返回yield关键字后的值。当生成器函数执行完毕时,通过调用next()函数会触发StopIteration异常。 通过这个例子,我们可以看到yield函数的实际应用:按需生成数据。在这个例子,我们可以在使用generate_numbers函数时,只生成需要的数据,而不是一次性生成所有的数字。这样可以极大地节省内存,并提高程序的性能。 总的来说,yield函数的实例分析可以帮助我们更好地理解和使用生成器函数,从而在需要按需生成数据的场景下提供更加高效的解决方案。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值