24. 生成器

一、什么是生成器

  利用迭代器,我们可以每次迭代获取数据(通过 next() 方法)时按照特定的规律进行生成。但是在实现一个迭代器时,关于当前迭代的状态需要我们自己记录,进而才能根据当前状态生成下一个数据。为了达到记录当前状态,并配合 next() 函数进行迭代使用。简而言之,迭代器时可以实现在循环的过程中生成数据时,但是稍微有些复杂。

class PointXY:
    def __init__(self):
        self.x = 0
        self.k = 2
        self.b = 1
  
    def __iter__(self):
        return self
  
    def __next__(self):
        # y = kx + b
        temp_y = self.k * self.x + self.b
        temp_point_x_y = (self.x, temp_y)
        self.x = temp_y
        return temp_point_x_y
  
    def change_k_b(self, k, b):
        self.k = k
        self.b = b
  
point_x_y = PointXY()
point_x_y_iter = iter(point_x_y)

i = 0
while i < 5:
    if i == 3:
        point_x_y.change_k_b(3, 2)
  
    point_x_y_value = next(point_x_y_iter)
    print(point_x_y_value)
    i += 1

  我们可以使用生成器简化这个过程,生成器就是一类特殊的迭代器。生成器只记录生成数据的方式(算法),而不是事先生成存储这些数据,这种方式就称之为 生成器(generator)。

  在函数内,我们可以使用 yield 关键字时,调用该函数时并不会执行函数体代码,而是会返回一个生成器对象。调用生成器的 __next__() 方法会触发函数体代码的运行,然后遇到 yield 停下来,将 yield 后的值当做本次调用的结果返回。

  第一次执行时,则从函数开头开始执行,直到遇到 yield 关键字为止,并且把 yield 关键字后的数值返回,当作 next() 方法的返回值。如果不是第一次执行,则从上一次暂停的位置执行(即上一次 yield 关键字的下一条语句开始执行),直到遇到下一个 yield 关键字为止,并且将 yield 关键后的数值返回,当作 next() 方法的返回值。

  如果在调用 next() 方法时,从上一次暂停的地方继续向下执行,遇不到 yield 关键字,那么就会产生 StopIterationStop 异常。如果在调用 next() 方法时,接下来没有遇不到 yield 关键字,而是遇到 return关键字,那么就会产生 StopIterationStop 异常,并且会把 return 的数值用异常对象暂时存储起来。

def func():
    print("第一次执行!")
    yield 1
    print("第二次执行!")
    yield 2
    print("第三次执行!")
    yield 3
    print("第四次执行!")
    return 4

generate = func()
print(generate)
print(type(generate))
print()

while True:
    try:
        result = next(generate)
        print(result)
    except StopIteration as e:
        print(e.value)
        break

只要函数有 yield 关键字,就是生成器对象;

二、yield表达式

  如果想要生成器继续向下开始运行,我们可以使用 nest() 方法或 send() 方法,它们都会让生成器继续向下运行。并且,如果运行时,遇不到 yield 关键字都会产生异常。不同的是,next() 方法只会让运行继续开始,而 send() 方法除了让其开始运行之外,还可以将某个数据携带过去。

def dog(name):
    fodd_list = []
    print("小狗开始吃东西啦。")
    while True:
        # x拿到的是yield接收到的值
        x = yield fodd_list
        print(f"小狗{name}吃了{x}")
        fodd_list.append(x)

generate = dog("旺财")

# 首次使用send()方法时不能传值
result = generate.send(None)         # 相当于next(generate)
print(result,end="\n\n")

result = generate.send("大骨头")
print(result,end="\n\n")

result = generate.send("肉包子")
print(result,end="\n\n")

generate.close()
#result = generate.send("骨头汤")     # 关闭以后无法传值
posted @ 2024-10-28 18:25  星光映梦  阅读(3)  评论(0编辑  收藏  举报