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/archive%40mail-archive.com