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   |   [EMAIL PROTECTED]   |   Brisbane, Australia
---------------------------------------------------------------
            http://boredomandlaziness.skystorm.net
_______________________________________________
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

Reply via email to