使用生成器发送方法.仍然试图理解发送方法和古怪的行为 [英] Send method using generator. still trying to understand the send method and quirky behaviour

查看:57
本文介绍了使用生成器发送方法.仍然试图理解发送方法和古怪的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我为了理解发送方法而写的一个小函数:

<预><代码>>>>定义测试():... 对于 x 范围内的 x(10):... res = 产量...产量资源>>>a = 测试()>>>下一个(一)>>>下一个(一)>>>下一个(一)>>>下一个(一)>>>a.发送(0)回溯(最近一次调用最后一次):<ipython-input-220-4abef3782000>在 <module>()停止迭代>>>a = 测试()>>>a.发送(0)回溯(最近一次调用最后一次):<ipython-input-222-4abef3782000>在 <module>()类型错误:无法将非 None 值发送到刚启动的生成器>>>a.发送(无)>>>a.发送(0)0>>>a.发送(0)>>>a.发送(0)0>>>a.发送(0)>>>a.发送(0)0>>>a.发送(0)

为什么第一次出现错误?

<预><代码>>>>a.发送(0)停止迭代

为什么第一个 send() 需要为 None?与此错误一样:

<预><代码>>>>a.发送(0)回溯(最近一次调用最后一次):<ipython-input-222-4abef3782000>在 <module>()类型错误:无法将非 None 值发送到刚启动的生成器

然后第一次发送启动生成器(我不知道为什么),我发送一个0"并打印它,但第二个 0 再次没有,并继续我发送的任何内容(此处为 0)

<预><代码>>>>a.发送(无)>>>a.发送(0)0>>>a.发送(0)>>>a.发送(0)0>>>a.发送(0)>>>a.发送(0)0

此链接没有太大帮助Python 3:生成器的发送方法

解决方案

问题 1:为什么第一次出现错误?

第一次没有报错,在python2.7和python3.3上测试过:

<预><代码>>>>定义测试():... 对于 x 范围内的 x(10):... res = 产量...产量资源...>>>a = 测试()>>>下一个(一)>>>下一个(一)>>>下一个(一)>>>下一个(一)>>>a.发送(0)>>>a.发送(0)0>>>a.发送(0)>>>a.发送(0)0

问题 2:为什么第一个 send() 需要为 None?

你不能在第一次send()一个值,因为生成器直到你有yield语句的时候才执行,所以与值无关.>

这是来自 pep 的相关段落,它介绍了带有生成器的协同例程的特性(http://www.python.org/dev/peps/pep-0342/):

<块引用>

因为生成器-迭代器从顶部开始执行生成器的函数体,没有要接收的 yield 表达式生成器刚创建时的值.所以,禁止使用非 None 参数调用 send()生成器迭代器刚刚启动,如果出现 TypeError 则引发发生这种情况(大概是由于某种逻辑错误).因此,在您可以与协程通信之前,您必须首先调用next() 或 send(None) 将其执行推进到第一个收益表达

一个小小的演练:

def coro():在产量之前打印a = yield '屈服值'b = 产量 a打印完成!"c=coro() # 这不执行生成器,只创建它# 如果你在这里使用 c.send('a value') 它可以_不_对值做任何事情# 所以它会引发一个 TypeError!请记住,生成器尚未执行,# 只创建,就像执行在`print 'before yield'`之前# 这一行也可以是 `c.send(None)`,`None` 需要显式使用# 第一次使用 `send()` 表示你知道它是第一次迭代print next(c) # 将打印'before yield' 然后'the yield value' 就是yieldprint c.send('first value sent') # 将打印'first value sent'# 将打印完成!"# 字符串 'the second value sent' 已发送但未使用,将引发 StopIterateprint c.send('发送的第二个值')print c.send('oops') # 引发停止迭代

Here is a little function i wrote to understand the send method:

>>> def test():
...     for x in xrange(10):
...         res = yield
...         yield res
>>> a = test()
>>> next(a)
>>> next(a)
>>> next(a)
>>> next(a)
>>> a.send(0)
Traceback (most recent call last):
   <ipython-input-220-4abef3782000> in <module>()
StopIteration
>>> a = test()
>>> a.send(0)
Traceback (most recent call last):
   <ipython-input-222-4abef3782000> in <module>()    
TypeError: can't send non-None value to a just-started generator
>>> a.send(None)
>>> a.send(0)
0
>>> a.send(0)
>>> a.send(0)
0
>>> a.send(0)
>>> a.send(0)
0
>>> a.send(0)

Why is there an Error the first time?

>>> a.send(0)
StopIteration 

Why does it require for the first send() to be None? as with this error:

>>> a.send(0)
Traceback (most recent call last):
    <ipython-input-222-4abef3782000> in <module>()
TypeError: can't send non-None value to a just-started generator

And then the first send starts the generator( i dont know why) and i send a '0' and it prints it but the second 0 is again none and resumes with whatever i send it(0 here)

>>> a.send(None)
>>> a.send(0)
0
>>> a.send(0)
>>> a.send(0)
0
>>> a.send(0)
>>> a.send(0)
0

This link doesnt help much Python 3: send method of generators

解决方案

Question 1: Why is there an Error the first time?

There is no Error the first time, tested on python2.7 and python3.3:

>>> def test():
...     for x in xrange(10):
...         res = yield
...         yield res
... 
>>> a = test()
>>> next(a)
>>> next(a)
>>> next(a)
>>> next(a)
>>> a.send(0)
>>> a.send(0)
0
>>> a.send(0)
>>> a.send(0)
0

Question 2: Why does it require for the first send() to be None?

You can't send() a value the first time because the generator did not execute until the point where you have the yield statement, so there is nothing to do with the value.

Here is the relevant paragraph from the pep that introduced the feature of co-routines with generators (http://www.python.org/dev/peps/pep-0342/):

Because generator-iterators begin execution at the top of the generator's function body, there is no yield expression to receive a value when the generator has just been created. Therefore, calling send() with a non-None argument is prohibited when the generator iterator has just started, and a TypeError is raised if this occurs (presumably due to a logic error of some kind). Thus, before you can communicate with a coroutine you must first call next() or send(None) to advance its execution to the first yield expression

A tiny walkthrough:

def coro():
   print 'before yield'
   a = yield 'the yield value'
   b = yield a
   print 'done!'
 c=coro() # this does not execute the generator, only creates it

 # If you use c.send('a value') here it could _not_ do anything with the value
 # so it raises an TypeError! Remember, the generator was not executed yet,
 # only created, it is like the execution is before the `print 'before yield'`

 # This line could be `c.send(None)` too, the `None` needs to be explicit with
 # the first use of `send()` to show that you know it is the first iteration
 print next(c) # will print 'before yield' then 'the yield value' that was yield

 print c.send('first value sent') # will print 'first value sent'

 # will print 'done!'
 # the string 'the second value sent' is sent but not used and StopIterating will be raised     
 print c.send('the second value sent') 

 print c.send('oops') # raises StopIterating

这篇关于使用生成器发送方法.仍然试图理解发送方法和古怪的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆