前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【从零学习python 】60.探索生成器:迭代的灵活利器

【从零学习python 】60.探索生成器:迭代的灵活利器

作者头像
全栈若城
发布2024-02-29 20:14:12
910
发布2024-02-29 20:14:12
举报
文章被收录于专栏:若城技术专栏

生成器

1. 生成器

利用迭代器,我们可以在每次迭代获取数据(通过next()方法)时按照特定的规律进行生成。但是我们在实现一个迭代器时,关于当前迭代到的状态需要我们自己记录,进而才能根据当前状态生成下一个数据。为了达到记录当前状态,并配合next()函数进行迭代使用,我们可以采用更简便的语法,即生成器(generator)。生成器是一类特殊的迭代器。

2. 创建生成器方法1

要创建一个生成器,有很多种方法。第一种方法很简单,只要把一个列表生成式的 [ ] 改成 ( )

代码语言:javascript
复制
L = [x * 2 for x in range(5)]
G = (x * 2 for x in range(5))

创建 L 和 G 的区别仅在于最外层的 [ ] 和 ( ) , L 是一个列表,而 G 是一个生成器。我们可以直接打印出列表L的每一个元素,而对于生成器G,我们可以按照迭代器的使用方法来使用,即可以通过next()函数、for循环、list()等方法使用。

代码语言:javascript
复制
next(G) # 输出 0
next(G) # 输出 2
next(G) # 输出 4
next(G) # 输出 6
next(G) # 输出 8
代码语言:javascript
复制
G = (x * 2 for x in range(5))
for x in G:
    print(x)

输出结果为:

代码语言:javascript
复制
0
2
4
6
8

3. 创建生成器方法2

generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

我们仍然用上一节提到的斐波那契数列来举例,回想我们在上一节用迭代器的实现方式:

代码语言:javascript
复制
class FibIterator(object):
    """斐波那契数列迭代器"""
    def __init__(self, n):
        """
        :param n: int, 指明生成数列的前n个数
        """
        self.n = n
        # current用来保存当前生成到数列中的第几个数了
        self.current = 0
        # num1用来保存前前一个数,初始值为数列中的第一个数0
        self.num1 = 0
        # num2用来保存前一个数,初始值为数列中的第二个数1
        self.num2 = 1

    def __next__(self):
        """被next()函数调用来获取下一个数"""
        if self.current < self.n:
            num = self.num1
            self.num1, self.num2 = self.num2, self.num1+self.num2
            self.current += 1
            return num
        else:
            raise StopIteration

    def __iter__(self):
        """迭代器的__iter__返回自身即可"""
        return self

注意,在用迭代器实现的方式中,我们要借助几个变量(n、current、num1、num2)来保存迭代的状态。现在我们用生成器来实现一下。

代码语言:javascript
复制
def fib(n):
    current = 0
    num1, num2 = 0, 1
    while current < n:
        yield num1
        num1, num2 = num2, num1+num2
        current += 1
    return 'done'

4. 使用send唤醒

我们除了可以使用next()函数来唤醒生成器继续执行外,还可以使用send()函数来唤醒执行。使用send()函数的一个好处是可以在唤醒的同时向断点处传入一个附加数据。

例子:执行到yield时,gen函数作用暂时保存,返回i的值; temp接收下次c.send(“python”),send发送过来的值,c.next()等价c.send(None)

代码语言:javascript
复制
def gen():
    i = 0
    while i<5:
        temp = yield i
        print(temp)
        i+=1

使用send

代码语言:javascript
复制
f = gen()
next(f)  # 输出 0
f.send('haha')  # 输出 haha
next(f)  # 输出 None
f.send('haha')  # 输出 haha

使用next函数

代码语言:javascript
复制
f = gen()
next(f)  # 输出 0
next(f)  # 输出 None
next(f)  # 输出 None
next(f)  # 输出 None
next(f)  # 输出 None
next(f)  # 抛出 StopIteration 异常

使用__next__()方法(不常使用)

代码语言:javascript
复制
f = gen()
f.__next__()  # 输出 0
f.__next__()  # 输出 None
f.__next__()  # 输出 None
f.__next__()  # 输出 None
f.__next__()  # 输出 None
f.__next__()  # 抛出 StopIteration 异常

以上就是生成器的基本用法。生成器在迭代过程中可以暂停和继续,非常灵活,适合处理大量的数据或者需要延迟生成的数据。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-02-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 生成器
    • 1. 生成器
      • 2. 创建生成器方法1
        • 3. 创建生成器方法2
          • 4. 使用send唤醒
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档