I thought I could make my python (2.7.10) code simpler by directly accessing the index of a value passed to a generator via send
, and was surprised the code ran. I then discovered an index applied to yield
doesn't really do anything, nor does it throw an exception:
def gen1():
t = yield[0]
assert t
yield False
g = gen1()
next(g)
g.send('char_str')
However, if I try to index yield
thrice or more, I get an exception:
def gen1():
t = yield[0][0][0]
assert t
yield False
g = gen1()
next(g)
g.send('char_str')
which throws
TypeError: 'int' object has no attribute '__getitem__'
This was unusually inconsistent behavior, and I was wondering if there is an intuitive explanation for what indexing yield is actually doing?
You are not indexing. You are yielding a list; the expression yield[0]
is really just the same as the following (but without a variable):
lst = [0]
yield lst
If you look at what next()
returned you'd have gotten that list:
>>> def gen1():
... t = yield[0]
... assert t
... yield False
...
>>> g = gen1()
>>> next(g)
[0]
You don't have to have a space between yield
and the [0]
, that's all.
The exception is caused by you trying to apply the subscription to the contained 0
integer:
>>> [0] # list with one element, the int value 0
[0]
>>> [0][0] # indexing the first element, so 0
0
>>> [0][0][0] # trying to index the 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not subscriptable
If you want to index a value sent to the generator, put parentheses around the yield
expression:
t = (yield)[0]
Demo:
>>> def gen1():
... t = (yield)[0]
... print 'Received: {!r}'.format(t)
... yield False
...
>>> g = gen1()
>>> next(g)
>>> g.send('foo')
Received: 'f'
False
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With