Guido van Rossum <[EMAIL PROTECTED]> writes: > I just read Raymond Chen's rant against control flow macros: > http://blogs.msdn.com/oldnewthing/archive/2005/01/06/347666.aspx > > I think this pretty much kills PEP 340, as well as Nick Coghlan's > alternative: both proposals let you write a "template" that can be > used to hide exception-catching code, which is a form of control flow > (and a pretty important one if you read Chen's rant against exceptions > referenced by the former, even if you don't agree with everything he > says in the latter).
Well, I'm not sure what the content of the latter article is, other than "getting things right can be hard". BTW, the "else:" on try statements is so very handy for getting this sort of thing (more) corrent. > Which leaves us, IMO, with the choice between PEP 310 and my own > "PEP-340-redux" proposal; these *only* introduce a finally-clause, > which does not affect the control flow. I'm not counting exceptions > that might happen in the finally-clause; exceptions can happen > anywhere anyway. But I am counting the *catching* of an exception as > control flow, since that means that code past BLOCK (in the same > function) is reachable even if BLOCK was not executed to completion; > and this is the argument against PEP 340 and against Nick's > alternative. > > Let's compare and contrast the two remaining competitors: > > PEP 310 > ======= > > Syntax: > with EXPR [= VAR]: > BLOCK > > Translation: > [VAR =] abc = EXPR > if hasattr(abc, "__enter__"): > abc.__enter__() > try: > BLOCK > finally: > abc.__exit__() > > Pros: > - dead simple > > Cons: > - can't use a decorated generator for EXPR Sorry, why not? [note: I work this out, below, but I still think the code is worth posting] import sys class BlockTemplate(object): def __init__(self, g, args, kw): self.g = g self.args = args self.kw = kw def __enter__(self): self.giter = self.g(*self.args) self.giter.next() def __exit__(self): try: self.giter.next() except StopIteration: pass else: raise RuntimeError, "generator not exhausted" def template(g): def _(*args, **kw): return BlockTemplate(g, args, kw) return _ @template def redirected_stdout(out): print 'hi' save_stdout = sys.stdout sys.stdout = out yield None sys.stdout = save_stdout print 'ho' ## with redirected_stdout(fileobj): ## print 1 output = open("foo", "w") abc = redirected_stdout(output) abc.__enter__() try: print 1 finally: abc.__exit__() output.close() print repr(open("foo").read()) (this was a bit harder to get right than I expected, mind). Oh, I guess the point is that with a decorated generator you can yield a value to be used as VAR, rather than just discarding the value as here. Hmm. > PEP 340 redux > ============= > > Syntax: > do EXPR [as VAR]: > BLOCK > > Translation: > abc = EXPR > [VAR =] abc.__enter__() > try: > BLOCK > finally: > abc.__exit__(*"sys.exc_info()") # Not exactly These two expansions look very similar to me. What am I missing? > Pros: > - can use a decorated generator as EXPR > - separation of EXPR and VAR (VAR gets what EXPR.__enter__() returns) Oh! Hmm. This is a bit subtle. I guess I should think about some examples. > Cons: > - slightly less simple (__enter__ must return something for VAR; > __exit__ takes optional args) If things were fiddled such that sys.exc_info() return non-Nones when a finally clause is being executed because of an exception, we don't really need this wart, do we? > Everything else is equal or can be made equal. We can make them more > equal by treating the arguments passed to __exit__() as a separate > decision, and waffling about whether __enter__() should be optional (I > think it's a bad idea even for PEP 310; it *could* be made optional > for PEP 340 redux). I don't really recall why it's optional in PEP 310. > Let's also not quibble about the keyword used; again, that can be a > separate decision. Note that only PEP 310 can use the "VAR = EXPR" > syntax; PEP 340 redux *must* use "EXPR as VAR" since it doesn't assign > the value of EXPR to VAR; PEP 310 can be rewritten using this syntax > as well. > > So then the all-important question I want to pose is: do we like the > idea of using a (degenerate, decorated) generator as a "template" for > the do-statement enough to accept the slightly increased complexity? Looking at my above code, no (even though I think I've rendered the point moot...). Compare and contrast: @template def redirected_stdout(out): save_stdout = sys.stdout sys.stdout = out yield None sys.stdout = save_stdout class redirected_stdout(object): def __init__(self, output): self.output = output def __enter__(self): self.save_stdout = sys.stdout sys.stdout = self.output def __exit__(self): sys.stdout = self.save_stdout The former is shorter and contains less (well, no) 'self.'s, but I think I find the latter somewhat clearer. > The added complexity is caused by the need to separate VAR from EXPR > so that a generator can be used. I personally like this separation; I > actually like that the "anonymous block controller" is logically > separate from the variable bound by the construct. Nevertheless, I think I actually like this argument! > From Greg Ewing's response to the proposal to endow file objects > with __enter__ and __exit__ methods, I believe he thinks so too. > > Straight up-or-down votes in the full senate are appreciated at this point. +1 for the PEP 340 variant. > On to the secondary questions: > > - Today I like the 'do' keyword better; 'with' might confuse folks > coming from Pascal or VB No opinion. > - I have a more elaborate proposal for __exit__'s arguments. Let the > translation be as follows: > > abc = EXPR > [VAR =] abc.__enter__() > oke = False # Pronounced "okay" > exc = () > try: > try: > BLOCK > oke = True > except: > exc = sys.exc_info() > raise > finally: > abc.__exit__(oke, *exc) -"a bit" > PS. I've come up with another interesting use case: block signals for > the duration of a block. This could be a function in the signal > module, e.g. signal.blocking([ist of signals to block]). The list > would default to all signals. Similar signal.ignoring(). First you need to hit the authors of various libcs with big sticks. Cheers, mwh -- <shapr> ucking keyoar -- from Twisted.Quotes _______________________________________________ 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