Well, that was a head scratcher...

Skip Montanaro skip.montanaro at gmail.com
Mon Feb 23 12:23:44 EST 2015


I've been reworking some of the code in the platform I use at work.
I'm the sole developer/maintainer/hard-core user left, so I can pretty
much do what I want with it (convert modules to Cython, delete no
longer used modules, etc).  The platform uses PyGtk, so we use signals
and other features of that system heavily. In one place, I register a
generator function with gobject.idle_add:

    self.chunk_id = gobject.idle_add(self.read_chunk().next,
                                     priority=gobject.PRIORITY_LOW)

read_chunk is (as you might expect) a generator function.
Structurally, it looks like this:

    def read_chunk(self):
        count = 0
        while True:
            try:
                x = other_stuff()
            except StopIteration:
                yield False
            else:
                if some other condition holds:
                    yield False
                self.distribute(x)
            count += 1
            if count % 1000 == 0:
                # Let other folks have the CPU...
                yield True

I decided I needed to clean up that idle_add stuff when complete, so
instead of duplicating that bit before both "yield False" statements,
I wrapped the whole mess in a try/finally statement and did my cleanup
in the finally clause.  Thinking the "yield False" might circumvent
the finally clause (silly me), I changed those statements to break
statements.

Everything seemed to work okay for awhile, as long as I was running in
one (historical) mode, where the system only runs from historical data
(read_chunk above is responsible for much of that), exiting when the
historical data were exhausted.  When I switched to live mode
(initialize from historical data, then switch to listen for live
data), the system kept crashing with a StopIteration before switching
to live mode.

I thought I had handled all the StopIteration exceptions, but the
switch from "yield False" to "break" meant another one was raised
which I wasn't catching. Switching back to the yield statement solved
the problem. Took awhile to figure out what was going on.

Skip



More information about the Python-list mailing list