报料yield关键字的秘闻面纱

图片 1

报料yield关键字的秘闻面纱

写在前言

1.迭代

在明白生成器在此以前,先驾驭迭代。

时常会映重视帘,python函数中带有yield关键字,那么yield是什么,有如何效劳?

1.1 迭代

设若给定一个list或tuple,大家能够通过for循环来遍历那几个list或tuple,这种遍历大家誉为迭代(Iteration)

alist = [1, 2, 3, 4, 5]

for i in alist:
    print(i)

1
2
3
4
5

正如将列表中的成分通过for循环,遍历了全副alist列表,这种不重复地惠及其里面包车型大巴每贰个子项的作为正是迭代。

 

1.2 可迭代对象

能够平素效果于for循环的目标统称为可迭代对象:Iterable,可迭代对象日常都贯彻了__iter()__方式,可迭代对象通过其内建的方__iter()__重返八个迭代器对象。

a_iterable = [1, 2, 3]

a_iterator = iter(a_iterable)  # 将可迭代对象转化为迭代器

next(a_iterator)

1

next(a_iterator)

2

next(a_iterator)

3

答案:能够精晓yield是三个生成器;

1.3 迭代器

能够被next()函数调用并不仅仅重返下一个值的靶子称为迭代器:Iterator,迭代器其内实现了__iter__方法和__next__方法,for循环本质是透过调用可迭代对象的__iter__措施,该办法重回三个迭代器对象,再用__next__方式遍历成分

概念叁个迭代器:

class MyRange:
    def __init__(self, end):
        self.index = 0
        self.end = end

    def __iter__(self):
        return self

    def __next__(self):
        if self.index < self.end:
            val = self.index
            self.index += 1
            return val
        else:
            raise StopIteration()

my_range = MyRange(3)

print([i for i in my_range])

[0, 1, 2]

print([i for i in my_range])

[]

迭代器只好迭代贰遍,每一遍调用调用 next()
方法就能够上前一步,不能够后退,所以当迭代器迭代到最后时,就不得以另行利用,全部须要将迭代器和可迭代对象分别定义

修改上边的可迭代对象:

class MyRange:
    def __init__(self, end):
        self.end = end

    def __iter__(self):
        return MyIterator(self.end)

class MyIterator:
    def __init__(self, end):
        self.index = 0
        self.end = end

    def __iter__(self):
        return self    

    def __next__(self):
        if self.index < self.end:
            val = self.index
            self.index += 1
            return val
        else:
            raise StopIteration()

my_range = MyRange(3)

print([i for i in my_range])

[0, 1, 2]

print([i for i in my_range])

[0, 1, 2]

功用:境遇yield关键字,函数会向来回到yield值,也就是return;区别的是后一次调用的时候会从yield之后的代码开头实施。

2. 生成器

生成器与可迭代对象、迭代器的涉及

图片 1

图片来自Iterables vs. Iterators vs.
Generators

生成器对象,在历次调用它的next()方法时重回八个值,直到它抛出StopInteration。

生成器是足以迭代的,然而你 只可以够读取它一回,因为它并不把全部的值放在内部存款和储蓄器中,它是实时地变化数据,
能够用生成器说明式创造:

my_generator = (x ** 2 for x in range(3))

my_generator

<generator object <genexpr> at 0x7f975b7a4af0>

for i in my_generator:
    print(i)

0
1
4

yield

能够写贰个日常性的包涵yield语句的Python函数,Python会检查评定对yield的行使并将函数标识为四个生成器,当函数施行到yield语句时,像return语句那样重返贰个值,可是解释器会保存对栈的援引,它会被用来在下壹遍调用next时回涨函数。

def my_generator():
    yield 1
    yield 2
    yield 'a'
    yield 'generator'

g = my_generator()

g

<generator object my_generator at 0x7f975b7a4d58>

next(g)

1

next(g)

2

next(g)

'a'

next(g)

'generator'

next(g)

---------------------------------------------------------------------------

StopIteration                             Traceback (most recent call last)

<ipython-input-12-5f315c5de15b> in <module>()
----> 1 next(g)


StopIteration: 

上边的例子中,每一次调用next()开端实时地生成数据,并回到,因而生成器只可读取一回,上次实施读取的值在下一次执行中就不能够读取。当全体生成器的值都被读取后,在调用时机合世StopIteration的谬误。

def my_gen():
    for i in range(5):
        yield i ** 3

my_gen()

<generator object my_gen at 0x7f975ae15a40>

mygen = my_gen()

for i in mygen:
    print(i)

0
1
8
27
64

老是实行到yield语句,则赶回三个值,再实施的时候从上次停下来的地点早先实行。yield语句保存了上次推行后的情状,下一次实施不是从头最初,而是从上次的状态初叶。

当调用my_gen()这一个函数的时候,函数内部的代码不会及时试行,而是重临三个生成器对象,当使用for循环举行遍历的时候,函数内部的代码初叶实行,实践到yield表明式重临三个值,记录当前状态并终止,下一遍的探访时再从那些情状开始执行。

举八个不太方便的事例,普通的函数正是未有存档的娱乐,只要游戏开首,就玩到结尾,下叁回再玩依然从头早先,而生成器就是加了存档,后一次玩从上次存档之处初阶

 

关于生成器的思念

(瞎掰的。。。。)生成器到底起到哪边吗成效吗,就算生成贰个生成器对象,而生成器对象自然是二个迭代器,所以能够如此说,生成器重回了二个方可用for循环遍历所以子项,能够用next()方法访谈下叁个子项,能够在寻访时动态的变型数据而节省外部存款和储蓄器的对象。

生成器是如何?

阅读

一心知晓 Python
迭代对象、迭代器、生成器
对 Python
迭代的刻骨铭心记钻研
Python迭代器和生成器
3.
(译)Python关键字yield的解释(stackoverflow)
Python之列表生成式、生成器、可迭代对象与迭代器

是足以迭代的,可是你
只好够读取它一回
,因为它并不把装有的值放在内存中,它是实时地生成数据:

 

有人只怕会说,作者平昔迭代,遍历多好,为啥要用生成器,然后去遍历生成器,那多麻烦。

那么你要打听,list列表,全部数据是积累在内部存款和储蓄器中的。即便数据量非常的大,会特别耗内部存款和储蓄器。

 

 

yield是二个极度的return?

不等的是施行进度中境遇yield关键字,会阻断,yield
再次来到的是二个生成器。

先是次迭代中你的函数会进行,从开始到达
yield 关键字,然后重临 yield 后的值作为第三回迭代的归来值.

下一场,每便实践这几个函数都会继续实施你在函数内部定义的要命循环的后一次,再回到那些值,直到未有能够再次来到的。

 

小心,当函数中现身yield,该函数再次回到的便是三个生成器。不在是日常函数。

def func(num):
    n,a,b = 0,0,1
    while num > n:
        yield b  #阻断,返回b
        a,b = b,a + b
        n+=1

for i in  func(19): #func(19)是一个生成器,生成器只有调用时执行一次。所以这里用循环
    print i

 

除外for循环取值,你也足以通过next()来取下二个值。

t = func(19)
t.next()

 

admin

网站地图xml地图