跳转至

生成器


生成器其实就是一种特殊的迭代器, 用过yield语法实现

代码1

import math


# 2是最小的质数
number = 2


def is_prime_number(number):
    """判断传入数字是否是质数"""

    end = int(math.sqrt(number)) + 1
    for i in range(2, end):
        if math.remainder(number, i) == 0:
            return False
    return True


def generate_prime_number():
    """质数生成器"""

    global number

    while True:
        tmp = number
        number += 1
        if is_prime_number(tmp):
            yield tmp


def main():
    """输出100以内的所有质数"""

    for _ in range(24):
        print(next(generate_prime_number()), end=', ')
    print(next(generate_prime_number()))


if __name__ == '__main__':
    main()

输出:

2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97

解释:

使用了yield关键字的函数不再是普通函数,而是生成器(generator), 生成器是一类特殊的迭代器

yield关键字有两点作用:

  • 保存当前运行状态, 即遇到 yield 后暂停执行,即将生成器挂起
  • 将 yield 后面的值返回
  • 使用 next() 函数唤醒生成器从而继续执行

PS: 把列表推到式外面的[]换成()就是一个生成器, 然后可以使用next()方法输出其元素

代码2

def fibonacci_sequence(n):
    """斐波那契数列"""

    current = 0
    num1, num2 = 1, 1
    while current < n:
        num = num1
        num1, num2 = num2, num1 + num2
        current += 1
        yield num
    # 触发StopIteration异常时可返回的值
    return '没有了'


def main():
    fs = fibonacci_sequence(6)

    while True:
        try:
            print(next(fs))
        except StopIteration as e:
            print(e.value)
            break


if __name__ == '__main__':
    main()

输出:

1
1
2
3
5
8
没有了

解释:

当引发StopIteration异常时, 生成器函数fibonacci_sequence中return后的值可以被输出

main函数中必须先定义变量 fs = fibonacci_sequence(6), 再使用 next(fs)

否则会无限循环输出 1

因为每次都调用函数,都是一个新的实例,每次都都从第一个数据开始取

对比代码1, 并没有设置变量, 之所以直接调用的结果依旧正确, 是因为设置了一个全局变量, 每次调用的初始条件都不一样

生成器中还有一个send方法, 详情见: https://blog.csdn.net/qq_42103091/article/details/124995095