Reputation: 26879
I have a function bar(obj)
which returns successive values from an object until it's exhausted, at which point it returns False
(ignore the fact that it's not a method on Foo
, or that I'm returning integers – this is just an MVCE to demonstrate the consumption of something). I'd like to wrap that function in a generator so I can lazily iterate over the values, but I'm clearly missing some logic, because this doesn't work:
class Foo:
def __init__(self):
self.counter = 0
def inc(self):
if self.counter <= 9:
self.counter += 1
return self.counter
else:
return False
def bar(obj):
return obj.inc()
def iterbar(obj):
res = bar(obj)
if res:
yield res
else:
raise StopIteration
foo = Foo()
lazy = iterbar(foo)
next(lazy) # this yields 1, as expected
next(lazy) # this immediately raises StopIteration from somewhere other than iterbar
How can I modify iterbar
to work correctly?
Upvotes: 1
Views: 77
Reputation: 45806
You aren't looping to repeat the calls to bar
. Once you call next
a second time, it picks up where the yield
left off, gets to the end of the function, then indicates that by raising.
Just loop, then return
to stop:
def iterbar(obj):
while True:
res = bar(obj)
if res:
yield res
else:
return
Or, if you want to be fancy and have Python 3.8+, you can use an assignment expression to make this more terse:
def iterbar(obj):
while res := bar(obj):
yield res
Upvotes: 2