0
def prefixes(s):
    if s:
        yield from prefixes(s[:-1])
        yield s

t = prefixes('both')
next(t)

The next(t) returns 'b'. I'm just confused as to why this is because if we follow down the yield from statement, we will eventually end at yield from prefixes('') which would return None. In all my other tests yield from None raises a TypeError. Instead, this seems to just be ignored and prefixes('b') moves onto the next yield statement (? why does it do that?) to yield 'b'... Any ideas as to why? Would greatly appreciate an explanation.

Ahmad A.A
  • 749
  • 7
  • 15
WeyX
  • 11

2 Answers2

0

generators are lazy(on-demand) objects, you didn't exhaust your generator t, to exhaust your generator you can use:

list(t)
# ['b', 'bo', 'bot', 'both']

now if you use next(t) you will get the expected StopIteration

StopIteration                             Traceback (most recent call last)
<ipython-input-25-680ef78477e2> in <module>
      6 t = prefixes('both')
      7 list(t)
----> 8 next(t)

StopIteration: 

the if statement is "guaranteeing" that you have an end and you will never do None[:-1] to get the TypeError

kederrac
  • 16,819
  • 6
  • 32
  • 55
0

prefixes is wrapped in a generator that raises StopIteration when the function returns. When passed an empty string, prefixes skips any yields, reaches the end of its code block and returns, causing StopIteration. The return value doesn't matter, it is discarded

>>> next(prefixes(""))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

yield from suppresses the inner generator's StopIteration and lets the outer generator continue.

tdelaney
  • 73,364
  • 6
  • 83
  • 116