今天看啥  ›  专栏  ›  亓官劼

学点简单的Python之Python生成器

亓官劼  · CSDN  ·  · 2021-01-09 16:15

学点简单的Python之Python生成器

大家好,我叫亓官劼(qí guān jié ),在CSDN中记录学习的点滴历程,时光荏苒,未来可期,加油~博主目前仅在CSDN中写博客,唯一博客更新的地址为: 亓官劼的博客 ,同时正在尝试在B站中做一些内容分享,B站主页为: 亓官劼的B站主页

本文原创为亓官劼,请大家支持原创,部分平台一直在恶意盗取博主的文章!!!
若需联系博主,可以联系本人微信:qiguanjie2015


什么是生成器?生成器能够做什么

在Python中,使用了yield的函数被称为生成器,生成器返回的是一个迭代器的函数,只能用于迭代操作,在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。

生成器常用场景:例如我们需要生成一个有规律向前推进的列表,或者一个1-1亿的列表等等,当我们列表中元素数量十分大时,内存会爆栈。但是如何我们元素间是有规律的,则我们可以利用生成器来解决这个问题。

例如一个简单是生成器应用实例,利用生成器输出1-1亿的数。

list = (i for i in range(1,100000000))
for item in list:
    print(item)
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

注意这里使用的是 () 而不是列表的 [] 。如果使用列表,内存将会爆栈,程序直接卡死,各位小伙伴有兴趣的话可以自己尝试一下哦!

如何创建一个生成器?如何使用生成器?

那生成器只能生成这样连续的简单数列吗?当然不是!我们可以编写自己的生成器函数,例如我们编写一个斐波那契数列的生成器。

# 生成器函数 - 斐波那契数列
def fibonacci(n):
    # a为第一个数,b为第二个数,counter为当前是第几个,迭代向前推进
    a, b, counter = 0, 1, 0
    while True:
        if counter > n:
            return
        yield a
        a, b = b, a + b
        counter += 1


# fib 是一个迭代器,由生成器返回生成
fib = fibonacci(10)

for item in fib:
    print(item)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

输出为:

0
1
1
2
3
5
8
13
21
34
55
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

这里我们每次返回一个fibonacci数列的值,每次返回的值即通过yield返回的值,返回之后生成器中的状态保持不变,等待下一次调用,当下一次调用来时,继续运行直到通过yield返回下一个值,以此循环。生成器不是将所有数保存在数列中,而是一个迭代器,每次返回时向前迭代。

next()和send()函数

我们可以利用next( )函数来获取迭代器的下一个值,例如下面这个例子:

def gen():
    yield 1
    yield 2
    yield 3
    yield 4

# a是由生成器gen生成的一个迭代器
a = gen()
print(next(a))# 输出a中下一个值
print(next(a))# 输出a中下一个值
print(next(a))# 输出a中下一个值
print(next(a))# 输出a中下一个值
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

输出结果为:

1
2
3
4
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

生成器即是迭代器也是可迭代对象,即我们可以通过next来依次获取迭代器中的值,同时也可以通过之前例子中的迭代器直接获取。

当前例子中我们迭代器中只有四个值,那么当我们获取四个值之后再次调用 next(a) 时,便会抛出 StopIteration 异常,即当前迭代器没法继续向前迭代。

同时,我们也可以使用 send() 函数来获取下一个值,但是与 next() 函数不同的是, send() 函数需要一个参数,将这个参数发送到 yield 表达式的值。例如下面这个例子:

def gen():
    temp = yield 1
    print(temp)
    temp = yield 2
    print(temp)
    temp = yield 3
    print(temp)
    temp = yield 4
    print(temp)

# a是由生成器gen生成的一个迭代器
a = gen()
print(next(a))# 输出a中下一个值
print(next(a))# 输出a中下一个值
print(next(a))# 输出a中下一个值
print(next(a))# 输出a中下一个值
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

这时我们的输出为:

1
None
2
None
3
None
4
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这里与我们上面例子不同的是,我们每次 yield 返回后,将这个 yield 1 的值作为表达式赋值给 temp ,当我们直接使用 next() 获取时,这个表达式的值为 None ,同时我们发现只输出了三个 None ,这也验证了我们之前说的,每次调用下一个值后,我们会停留在 yield 的位置,保存所有状态,直到下一次调用才会继续向下走。

我们通过 send() 函数来获取下一个值时,我们在 send() 函数中传的参数将会作为 yield 1 表达式的值赋值给 temp ,例如下面的例子。

def gen():
    temp = yield 1
    print(temp)
    temp = yield 2
    print(temp)
    temp = yield 3
    print(temp)
    temp = yield 4
    print(temp)

# a是由生成器gen生成的一个迭代器
a = gen()
print(a.send(None))# 输出a中下一个值,第一次执行生成器代码的时候,send函数必须要传递None进去,否则会报错
print(a.send('qiguanjie1'))# 输出a中下一个值,并传入参数qiguanjie1给yield表达式
print(a.send('qiguanjie2'))# 输出a中下一个值,并传入参数qiguanjie2给yield表达式
print(a.send('qiguanjie3'))# 输出a中下一个值,并传入参数qiguanjie3给yield表达式
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

输出为:

1
qiguanjie1
2
qiguanjie2
3
qiguanjie3
4
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如果我们要使用 send() 来调用下一个值但我们不需要发送消息时,我们可以传递一个None进去,即 a.send(None)

好了,今天的学点简单的Python之Python生成器篇就到这里了,我们下次再见!如果这篇文章对您有帮助的话,可以点赞关注博主一下,给博主一些鼓励,哈哈~




原文地址:访问原文地址
快照地址: 访问文章快照