[Python-Dev] pre-PEP: Resource-Release Support for Generators

Guido van Rossum guido at python.org
Tue Aug 26 14:50:52 EDT 2003


> >      PEP 288 [2] proposes a more general solution, allowing custom
> >      exception passing to generators.
> 
> Is there any reason to prefer gen.close() over the more general solution
> gen.throw(Close) which results in nearly identical code and yet allows 
> other exception types to be handled as well?

After re-skimming PEP 288 I'm still not convinced that a more general
problem exists for which .close() isn't sufficient.  The one
motivating example there (writing a log file) seems forced and can be
done in other ways.

> Note, the general purpose solution is a natural extension of the existing
> syntax and is easily implemented without messing with 'try/finally'.

I don't understand this remark.  AFAICT PEP 288 doesn't propose new
syntax, only a new method and its semantics.  And I don't see
Samuele's solution as "messing with try/finally".

> Pretty much all that was holding up the general solution was that
> I had not convinced Guido that the clean-up problem exists in
> practice.  It looks like you've surmounted that obstacle for me.

But you still haven't convinced me of the need for the more
generalized PEP 288 mechanism.

I do think that the possibility of implementing PEP 288 in the future
suggests that Samuele's .close() should be implemented in terms of a
special exception, not in terms of a 'return'.

The spec needs to define clearly what should happen if the generator
catches and ignores the exception, e.g.:

  def forever():
      while True:
          try:
              yield None
          except:
              pass

  f = forever()
  f.next()
  f.close()

Clearly at this point the generator reaches the yield again.  What
should happen then?  Should it suspend so that a subsequent call to
f.next() can receive another value?  Or should reaching yield after
the generator is closed raise another exception?  I'm leaning towards
the latter, despite the fact that it will cause an infinite loop in
this case -- that's no different when you have a print statement
instead of a yield statement.

(Mentally substituting a print for a yield is often a useful way to
think about a generator.  The reverse can also be useful to consider
converting a non-generator to a generator: if it prints a sequence of
values, it can also yield the same sequence.)

Another comment on Samuele's PEP: It is sort of sad that the *user* of
a generator has to know that the generator's close() must be called.
Normally, the beauty of using a try/finally for cleanup is that your
callers don't need to know about it.  But I see no way around this.
And this is still an argument that pleads against the whole thing,
either PEP 288 or Samuele's smaller variant: the usual near-guarantee
that code in a finally clause will be executed no matter what (barring
fatal errors, os._exit() or os.execv()) does not apply.  And this was
the original argument against allowing yield inside try/finally.  But
the need for cleanup is also clear, so I like Samuele's KISS compromise.

--Guido van Rossum (home page: http://www.python.org/~guido/)



More information about the Python-Dev mailing list