Skip to content

Instantly share code, notes, and snippets.

@sigmavirus24
Created July 11, 2015 04:05
Show Gist options
  • Save sigmavirus24/318102d7db3cdd77e06e to your computer and use it in GitHub Desktop.
Save sigmavirus24/318102d7db3cdd77e06e to your computer and use it in GitHub Desktop.
class Iter(object):
def __init__(self, iterable):
self.iterable = iterable
self.closed = False
def __iter__(self):
try:
for chunk in self.iterable:
yield chunk
finally:
self.closed = True
iter = Iter(range(5))
try:
for i in iter:
raise IOError()
except IOError:
pass
assert iter.closed is True
@lrowe
Copy link

lrowe commented Jul 11, 2015

Rather than calling gc.collect which does not really guarantee that all garbage will be collected, you want to restructure things so that you manage resources in your main routine rather than the generator coroutine:

import contextlib


class FileLikeObject(object):
    def __init__(self):
        self.iter = [b"foo", b"bar", b"baz"]
        self.closed = False

    def __iter__(self):
        for i in self.iter:
            yield i

    def close(self):
        self.closed = True


class Iter(object):
    def __init__(self, iterable):
        self.iterable = iterable

    def __iter__(self):
        with contextlib.closing(self.iterable):
            for chunk in self.iterable:
                yield chunk


f = FileLikeObject()
with contextlib.closing(f):
    for i in Iter(f):
        break

assert f.closed is True

Otherwise you need to ensure that you explicitly close all generators:

import contextlib


class FileLikeObject(object):
    def __init__(self):
        self.iter = [b"foo", b"bar", b"baz"]
        self.closed = False

    def __iter__(self):
        for i in self.iter:
            yield i

    def close(self):
        self.closed = True


class Iter(object):
    def __init__(self):
        self.iterable = FileLikeObject()

    def __iter__(self):
        with contextlib.closing(self.iterable):
            for chunk in self.iterable:
                yield chunk


it = Iter()
iter_it = iter(it)
with contextlib.closing(iter_it):
    try:
        for i in iter_it:
            raise IOError()
    except IOError:
        pass

assert it.iterable.closed is True

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment