Michael Hudson wrote:
This is a non-starter, I hope. I really meant what I said in PEP 310 about loops being loops.
The more I play with this, the more I want the 'with' construct to NOT be a loop construct. The main reason is that it would be really nice to be able to write and use a multipart code template as: def template(): # pre_part_1 yield None # post_part_1 yield None # pre_part_2 yield None # post_part_2 yield None # pre_part_3 yield None # post_part_3 def user(): block = template() with block: # do_part_1 with block: # do_part_2 with block: # do_part_3 If 'with' is a looping construct, the above won't work, since the first usage will drain the template. Accordingly, I would like to suggest that 'with' revert to something resembling the PEP 310 definition: resource = EXPR if hasattr(resource, "__enter__"): VAR = resource.__enter__() else: VAR = None try: try: BODY except: raise # Force realisation of sys.exc_info() for use in __exit__() finally: if hasattr(resource, "__exit__"): VAR = resource.__exit__() else: VAR = None Generator objects could implement this protocol, with the following behaviour: def __enter__(): try: return self.next() except StopIteration: raise RuntimeError("Generator exhausted, unable to enter with block") def __exit__(): try: return self.next() except StopIteration: return None def __except__(*exc_info): pass def __no_except__(): pass Note that the code template can deal with exceptions quite happily by utilising sys.exc_info(), and that the result of the call to __enter__ is available *inside* the with block, while the result of the call to __exit__ is available *after* the block (useful for multi-part blocks). If I want to drain the template, then I can use a 'for' loop (albeit without the cleanup guarantees). Taking this route would mean that: * PEP 310 and the question of passing values or exceptions into iterators would again become orthogonal * Resources written using generator syntax aren't cluttered with the repetitive try/finally code PEP 310 is trying to eliminate * 'for' remains TOOW to write an iterative loop * it is possible to execute _different_ suites between each yield in the template block, rather than being constrained to a single suite as in the looping case. * no implications for the semantics of 'return', 'break', 'continue' * 'yield' would not be usable inside a with block, unless the AbortIteration concept was adopting for forcible generator termination. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- http://boredomandlaziness.skystorm.net