Py学习  »  Python

解锁Python生成器:双向通信和send()方法

新语数据故事汇 • 4 周前 • 197 次点击  

我们在短文《一文带您理解Python生成器(generator):高效利用内存的奥秘》中介绍了python 生成器(generator)的基本用法和特性。Python中的生成器(generator)提供了一种懒加载值的便捷方式,但你了解生成器也支持双向通信吗?接下来将深入探讨强大的“send()”方法和双向通信机制,解锁控制和交互生成器的新可能性。

理解下:x= yield y

我们看一下代码(生成器函数以接受输入)的执行结果:

def test():    x = yield 4    print('x is', x)    x = yield 5    print('x is', x)    x = yield 6    print('x is', x)
for x in test(): print(x,end=" ")

x = yield 4 这行代码:

  • 正常生成值 4

  • 检查是否使用 .send() 方法向生成器发送了任何内容

  • 如果使用 .send() 发送了内容,x 将取该值

  • 如果未发送任何内容,x 将为 None

在不使用 .send() 方法的情况下使用 next 迭代我们的生成器:

def test():    x = yield 4    print('x is', x)    x = yield 5    print('x is', x)    x = yield 6    print('x is', x)
gen = test()
print(next(gen))print(next(gen))print(next(gen))

  • 最后我们仍然生成了3个值:4、5和6,

  • 就像 yield 4,代码行 x = yield 4 仍然会生成4

  • 因为没有使用 .send(),x 一直都是 None

向生成器send数据

看下面示例代码的执行结果:

def test():    x = yield 4    print('x is', x)    x = yield 5    print('x is', x)    x = yield 6
gen = test()
print(next(gen))print(gen.send(100))print(next(gen))

注意到我将中间的 next(gen) 替换为 gen.send(100)

  • 第一次 next(gen) 发生,生成第一个值。

  • x = yield 4 运行。这首先生成值 4,并打印 4。

  • x = yield 4 中的 x 等待我们向它发送某些内容。

  • gen.send(100) 发生,x = yield 4 中的 x 接收 100。

  • x 是 100,因此打印 100。

  • gen.send(100) 还会生成一些内容,因此运行 x = yield 5,并生成值 5 并打印。

  • x = yield 5 中的 x 等待我们向它发送某些内容。

  • 但我们没有向它发送任何内容。相反,再次发生 next(gen)。

  • 因此,x = yield 5 中的 x 取值 None,并打印 x 是 None。

  • next(gen) 生成下一个值 6。


向生成器send 多次数据

观察一下代码和执行结果:

def test():    x = yield 4    print('x is', x)    x = yield 5    print('x is', x)    x = yield 6
gen = test()
print(next(gen))print(gen.send(100))print(gen.send('apple'))

上述代码中有两个 .send() 语句:

  • next(gen) 发生,x = yield 4 运行。我们打印 4。

  • x = yield 4 中的 x 等待我们发送某些内容。

  • gen.send(100) 发生,x 现在是 100。打印 x 是 100。

  • gen.send(100) 也会自动生成一些内容,因此 x = yield 5 运行,并打印 5。

  • gen.send('apple') 发生,x 现在是 'apple'。打印 x 是 'apple'。

  • gen.send('apple') 也会自动生成一些内容,因此 x = yield 6 运行,并打印 6。

更实际的例子:双向通信,逻辑控制的示例

我们需要一个生成器,它会永远计数 1、2、3、4、5…… 但是,如果我们向它发送一个值,生成器会从该数字继续计数。

def test():    n = 1    while True:        # yield n, and check if we .send() anything        value_from_send = yield n
if value_from_send is not None: # if we .send() something, replace n n = value_from_send else: # if we don't .sned() anything, just add 1 to n n += 1
gen = test()
print(next(gen)) print(next(gen)) print(next(gen)) print(next(gen)) print(next(gen))
  

如果我们不向生成器 .send() 任何内容,它会从 1 开始打印,并每次增加 1。现在让我们向生成器发送一些数据。

gen = test()
print(next(gen))print(next(gen))print(next(gen))print(gen.send(101))print(next(gen))print(next(gen))

  • 正常开始打印 1,然后是 2,然后是 3。

  • 接着我们 .send(101)。

  • 此时,value_from_send 是 101。

  • if 语句块运行,n 现在是 101。所以我们生成 101。

  • 之后,不再发生 .send(),我们继续以正常的 1 增量计数。


了解 Python 生成器的 send() 方法可以让你向生成器输入内容,从而完全控制生成器函数的迭代。这对于处理复杂的数据流和控制结构非常有用。此外,许多现有的生产代码使用了这种方法,因此掌握它是必需的。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/171506
 
197 次点击