Moreover, since the main use case seems to be fixing a corner case of the nested() context manager, perhaps the effort towards changing the language would be better directed towards supporting "with a, b:" as a shorthand for "with a: with b:" .
On Mon, Mar 16, 2009 at 10:01 AM, Guido van Rossum <gu...@python.org> wrote: > I have no right to speak because I haven't read through all the > details of the proposal, but reading this I am very sad that we have > to introduce a whole new exception (and one with special status as > well) in order to fix such a niggly corner case of the context manager > protocol. > > Since IIUC the original context manager design was intended to have > exactly one yield in the body of the context manager -- can't we just > declare fewer (or more) yields an error and rase an appropriate > TypeError or something? > > --Guido > > On Mon, Mar 16, 2009 at 4:43 AM, Nick Coghlan <ncogh...@gmail.com> wrote: >> Michael Foord wrote: >>> Well, StopIteration is still an implementation detail that only >>> occasionally bleeds through to actual programming. It says nothing about >>> whether using exceptions for non-exceptional circumstances (control >>> flow) is good practise. Personally I think it makes the intent of code >>> less easy to understand - in effect the exceptions *are* being used as a >>> goto. >> >> Note that raising SkipStatement manually is likely to be even rarer than >> raising StopIteration. Catching it should almost never happen other than >> implicitly inside a with statement (that's the reason I made it a peer >> of SystemExit and GeneratorExit rather than a peer of StopIteration). >> >> It is primarily proposed as a way for contextlib.contextmanager to tell >> the interpreter that the underlying generator didn't yield, so the body >> of the with statement should be skipped completely. It just so happens >> that manually implemented context managers will also be free to use it >> if they need to for some reason. >> >> An alternative approach worth considering may be to use NotImplemented >> as a model instead of StopIteration. With that approach, instead of >> having SkipStatement be an exception, have it be a singleton that can be >> returned from __enter__ to indicate that the with statement body would >> be skipped. >> >> That has a big advantage over using an exception when it comes to >> execution speed. The statement semantics in that case would become: >> >> mgr = (EXPR) >> exit = mgr.__exit__ # Not calling it yet >> value = mgr.__enter__() >> if value is not SkipStatement: >> exc = True >> try: >> try: >> VAR = value # Only if "as VAR" is present >> BLOCK >> except: >> # The exceptional case is handled here >> exc = False >> if not exit(*sys.exc_info()): >> raise >> # The exception is swallowed if exit() returns true >> finally: >> # The normal and non-local-goto cases are handled here >> if exc: >> exit(None, None, None) >> >> (keeping in mind that I already plan to change PEP 377 to drop the idea >> of assigning anything to VAR when the statement body is skipped) >> >> The major drawback of that approach is that it becomes a little trickier >> to write a context manager like nested() correctly - it would need to >> check all of the __enter__() return values and start unwinding the >> context manager stack if it encountered SkipStatement. The fix isn't >> particularly complicated*, but it does contrast with the fact that >> having SkipStatement as an exception means that the current >> implementation of nested() will "just work" with the new semantics. >> >> Cheers, >> Nick. >> >> * For reference, to support a "SkipStatement as return value" approach >> the main loop in nested() would have to change from this: >> >> for mgr in managers: >> exit = mgr.__exit__ >> enter = mgr.__enter__ >> vars.append(enter()) >> exits.append(exit) >> yield vars >> >> To this: >> >> for mgr in managers: >> exit = mgr.__exit__ >> enter = mgr.__enter__ >> var = enter() >> if var is SkipStatement: >> break >> vars.append(var) >> exits.append(exit) >> else: >> yield vars >> >> As mentioned above, if SkipStatement is an exception then nested() works >> correctly without any changes. >> >> -- >> Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia >> --------------------------------------------------------------- >> _______________________________________________ >> Python-Dev mailing list >> Python-Dev@python.org >> http://mail.python.org/mailman/listinfo/python-dev >> Unsubscribe: >> http://mail.python.org/mailman/options/python-dev/guido%40python.org >> > > > > -- > --Guido van Rossum (home page: http://www.python.org/~guido/) > -- --Guido van Rossum (home page: http://www.python.org/~guido/) _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com