[Python-ideas] Make "yield" inside a with statement a SyntaxError

Stephen J. Turnbull turnbull.stephen.fw at u.tsukuba.ac.jp
Wed Aug 8 04:13:49 EDT 2018


Ken Hilton writes:

 > Can you spot the problem? The "with open(filename)" statement is supposed
 > to ensure that the file object is disposed of properly. However, the "yield
 > f.read()" statement suspends execution within the with block, so if this
 > happened:
 > 
 >     for contents in read_multiple('chunk1', 'chunk2', 'chunk3'):
 >         if contents == 'hello':
 >             break
 > 
 > and the contents of "chunk2" were "hello" then the loop would exit, and
 > "chunk2" would never be closed! Yielding inside a with block, therefore,
 > doesn't make sense and can only lead to obscure bugs.

You have one example of a bad outcome.  That hardly shows that *no*
yield in a with block makes sense.  On the contrary Chris A's
suggestion that a function might yield multiple times within one
context manager seems valid, although it might be bad practice.

There's another possibility.  Context managers have general
initialize-operate-finalize semantics.  True, they *often* have the
simple form "return the value of *expr* bound to *var* at entry, clean
up the contents of *var* at exit".  But I find it easy to imagine that
there are situations where the __enter__ method is complex and the
__exit__ method is a no-op.  In that case the problem you identify
can't happen, and yielding inside such a context manager would be
harmless.  A third possibility is that the __exit__ method has
semantics like the "else" of "while ... else", where the "normal" use
case involves a break, but occasionally the input is exhausted, and
some "default" action needs to be taken.

I grant that I don't have examples of the latter (after all, writing
context managers is a relatively rare activity, and the resource
acquisition-and-release paradigm is prominent).  But Chris's point
about line-oriented generators seems both plausible and common.

His analysis of why the risk is small also seems plausible, so I would
say this problematic case (and it is problematic) is covered by the
"consenting adults" principle.

Steve


More information about the Python-ideas mailing list