How do I ensure that a generator gets properly closed?
As my comment mentioned, one way to properly structure this would be using the contextlib.contextmanager
to decorate your generator:
from typing import Iterator
import contextlib
@contextlib.contextmanager
def get_numbers() -> Iterator[int]:
acquire_some_resource()
try:
yield iter([1, 2, 3])
finally:
release_some_resource()
Then when you use the generator:
with get_numbers() as et:
for i in et:
if i % 2 == 0:
raise ValueError()
else:
print(i)
Result:
generating some numbers
1
done generating numbers
Traceback (most recent call last):
File "<pyshell#64>", line 4, in <module>
raise ValueError()
ValueError
This allows the contextmanager
decorator to manage your resources for you without worrying handling the release. If you're feeling courageous, you might even build your own context manager class with __enter__
and __exit__
function to handle your resource.
I think the key takeaway here is that since your generator is expected to manage a resource, you should either be using the with
statement or always be closing it afterwards, much like f = open(...)
should always follow with a f.close()