Reputation: 61
Do I have to write
def count10():
for i in range(10):
yield i
gen = count10()
for j in gen:
print(j)
gen.close()
to save memory, or just
def count10():
for i in range(10):
yield i
for j in count10():
print(j)
In fact I would like to learn details of lifecycle of Python generator but failed to find relevant resources.
Upvotes: 2
Views: 1019
Reputation: 44108
The close
method for generators came about in PEP 342:
Add a close() method for generator-iterators, which raises GeneratorExit at the point where the generator was paused. If the generator then raises StopIteration (by exiting normally, or due to already being closed) or GeneratorExit (by not catching the exception), close() returns to its caller. If the generator yields a value, a RuntimeError is raised. If the generator raises any other exception, it is propagated to the caller. close() does nothing if the generator has already exited due to an exception or normal exit.
Note the last sentence: close() does nothing if the generator has already exited due to an exception or normal exit.
Upvotes: 3
Reputation: 280380
You don't need to close
that generator.
close
-ing a generator isn't about saving memory. (close
-ing things is almost never about saving memory.) The idea behind the close
method on a generator is that you might stop iterating over a generator while it's still in the middle of a try
or with
:
def gen():
with something_important():
yield from range(10)
for i in gen():
if i == 5:
break
close
-ing a suspended generator throws a GeneratorExit
exception into the generator, with the intent of triggering finally
blocks and context manager __exit__
methods. Here, close
would cause the generator to run the __exit__
method of something_important()
. If you don't abandon a generator in the middle like this (or if your generator doesn't have any finally
or with
blocks, including in generators it delegates to with yield from
), then close
is unnecessary (and does nothing).
The memory management system usually runs close
for you, but to really ensure prompt closure across Python implementations, you'd have to replace code like
for thing in gen():
...
with
with contextlib.closing(gen()) as generator:
for thing in generator:
...
I've never seen anyone do this.
Upvotes: 7