Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Guido van Rossum [EMAIL PROTECTED] writes: [Michael Hudson, after much thinking aloud] Yeah, sorry about that :) 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. Right. (I thought it was worth quoting this for the benefit of other who went down the same trail but didn't quite make it to this destination.) 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? The problem is that sys.exc_info() almost always returns *something* -- it's usually the last exception that was *ever* caught, except in certain circumstances. Yeah, OK. I'll stop claiming to understand sys.exc_info() apart from the simple cases. [Michael again] 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. Tastes differ. I think the generator wins; more so when there's more state to remember. Certainly when there's more state to manage, yes. But both will be possible, so, *shrug*. It's not a big deal. [Michael quoting Guido] 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! (Repeated for the benefit of others.) I guess this means PEP 310 can be retracted. Finally, from PEP 343 rev 1.7: exc = () # Or (None, None, None) ? The latter, please. Cheers, mwh -- . - the pointyour article - . |- a long way | -- Christophe Rhodes, ucam.chat ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
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). 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 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 Pros: - can use a decorated generator as EXPR - separation of EXPR and VAR (VAR gets what EXPR.__enter__() returns) Cons: - slightly less simple (__enter__ must return something for VAR; __exit__ takes optional args) 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). 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? 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. 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. On to the secondary questions: - Today I like the 'do' keyword better; 'with' might confuse folks coming from Pascal or VB - 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) This means that __exit__ can be called with the following arguments: abc.__exit__(True) - normal completion of BLOCK abc.__exit__(False) - BLOCK was left by a non-local goto (break/continue/return) abc.__exit__(False, t, v, tb) - BLOCK was left by an exception (An alternative would be to always call it with 4 arguments, the last three being None in the first two cases.) If we adopt PEP 340 redux, it's up to the decorator for degenerate generators to decide how to pass this information into the generator; if we adopt PEP 342 (continue EXPR) at the same time, we can let the yield-expression return a 4-tuple (oke, t, v, tb). Most templates can ignore this information (so they can just use a yield-statement). 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(). -- --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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
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)
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
At 03:05 AM 5/13/2005 -0700, Guido van Rossum wrote: 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? Since the do protocol is now distinct from the iterator protocol, I don't believe a decorator is still required. The purpose of the decorator was to help reduce confusion between the block statement and a for loop. Since you can no longer swallow exceptions, there is no downside to using an existing generator as the target of a do statement. That is, the concern about generators catching StopIteration from a yield doesn't matter, as they will simply step through to their next yield statement, and then the original exception will propagate. 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. 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. On to the secondary questions: - Today I like the 'do' keyword better; 'with' might confuse folks coming from Pascal or VB +1 on do EXPR as VAR, where VAR may be any valid LHS of an assignment. This means that __exit__ can be called with the following arguments: abc.__exit__(True) - normal completion of BLOCK abc.__exit__(False) - BLOCK was left by a non-local goto (break/continue/return) abc.__exit__(False, t, v, tb) - BLOCK was left by an exception (An alternative would be to always call it with 4 arguments, the last three being None in the first two cases.) I'm not sure the extra argument is a good idea; doesn't this introduce the same sort of invisible control flow as swallowing exceptions? Also, since the block controller can't actually change the control flow, I'm having a hard time thinking of any actual use cases for this information. If we adopt PEP 340 redux, it's up to the decorator for degenerate generators to decide how to pass this information into the generator; if we adopt PEP 342 (continue EXPR) at the same time, we can let the yield-expression return a 4-tuple (oke, t, v, tb). Most templates can ignore this information (so they can just use a yield-statement). I was going to propose having a generator-iterator's __exit__() raise the triple inside the generator, or raise StopIteration inside the generator if there is no triple. I'd ideally also like close() as a synonym for __exit__() with no arguments. Although these are properly the subject of PEPs 288 and 325 respectively, I felt this would elegantly bring them both to closure. However, after thinking it through, I realized that I don't see any obvious way to make __exit__ reusable for PEPs 288 and 325, because for 288 at least, I'd want __exit__ to either return the next yielded value or raise StopIteration. But, this isn't compatible with the do protocol's needs, unless the do protocol suppressed StopIteration, and that doesn't seem like such a good idea. It seems to me that passing exceptions into a generator does in fact require a distinct method. But, I still do believe that generator-iterators can have predefined __enter__ and __exit__ methods without the need for a decorator. 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(). Sweet. You could also use it for temporary signal handling, i.e. set this signal handler for the duration of the block. Sort of the same class of make sure I restore a global I'm tampering with use case as redirecting stdout, and Tim Peters' Decimal context use cases. ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
[Michael Hudson, after much thinking aloud] 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. Right. (I thought it was worth quoting this for the benefit of other who went down the same trail but didn't quite make it to this destination.) 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? The problem is that sys.exc_info() almost always returns *something* -- it's usually the last exception that was *ever* caught, except in certain circumstances. Phillip wrote on the same issue: I'm not sure the extra argument is a good idea; doesn't this introduce the same sort of invisible control flow as swallowing exceptions? Also, since the block controller can't actually change the control flow, I'm having a hard time thinking of any actual use cases for this information. The 'oke' argument is so that the author of transactional() can decide what to do with a non-local goto: commit, rollback or hit the author over the head with a big stick. [Michael again] 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. Tastes differ. I think the generator wins; more so when there's more state to remember. [Michael quoting Guido] 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! (Repeated for the benefit of others.) Straight up-or-down votes in the full senate are appreciated at this point. +1 for the PEP 340 variant. -- --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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
At 08:41 AM 5/13/2005 -0700, Guido van Rossum wrote: The 'oke' argument is so that the author of transactional() can decide what to do with a non-local goto: commit, rollback or hit the author over the head with a big stick. Since this is just a replacement for a try/except/finally block, I'd expect that in a transactional case that a non-local goto would work the same as any other non-exception exit. ISTM that the resource block use cases are: * Save the current state of something, modify it, and then restore the old state once the block completes (try/finally, used for locking, redirection, signals, decimal context, etc.) * Automatically roll back partially-done work in case of exception, and/or roll forward completed work (try/except/else, used for transaction scenarios) * Release allocated resource(s) after use (try/finally, used to close files and suchlike) None of these, AFAICT, benefit from differing behavior in the presence of nonlinear (but non-exceptional) control flow. It just seems too magical to me in the new context. When we were talking about a block construct or user-defined syntax, it made more sense because you could actually redefine the *meaning* of those constructs to some extent -- and because the *target* of the break and continue statements at least was the block itself, not some containing block. ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
On 5/13/05, Guido van Rossum [EMAIL PROTECTED] wrote: 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? +0. I'm not thoroughly convinced that generators are that much easier to read than a class. But I don't find them hard to read, and I think it would only take a little effort to learn that generators might not always be intended to build iterators. If we do support generators in do-statements, I'd like their __enter__() and __exit__() methods (if possible) to have semantics like Nick Coghlan suggested[1], so that: * __enter__() raises an exception if next() has already been called, and * __exit__() raises an exception if StopIteration is not raised The first makes sure that the generator is only used once, and the second makes sure that there is only one yield on the given control path through the generator. In all but the most sick and twisted code, raising exceptions like this will be identifying errors in how the generator was written. Straight up-or-down votes in the full senate are appreciated at this point. +1 on the PEP 340 redux semantics. On to the secondary questions: - Today I like the 'do' keyword better; 'with' might confuse folks coming from Pascal or VB +1 on using 'do'. - I have a more elaborate proposal for __exit__'s arguments. Let the translation be as follows: [snip] abc.__exit__(True) - normal completion of BLOCK abc.__exit__(False) - BLOCK was left by a non-local goto (break/continue/return) abc.__exit__(False, t, v, tb) - BLOCK was left by an exception -1. This looks like a fair bit of added complexity for not much gain. The only example that even *might* make use of this was the transactional one, and I haven't yet seen a use case where it actually *is*. The simpler semantics give you the difference between a normal exit and an exceptional exit. I'd like to see an example that needs to know the difference between block completion exit and a break/continue/return exit before I'd want to make PEP 340 redux this much more complex. STeVe [1] http://members.iinet.net.au/~ncoghlan/public/pep-3XX.html -- You can wordify anything if you just verb it. --- Bucky Katt, Get Fuzzy ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
[Guido] The 'oke' argument is so that the author of transactional() can decide what to do with a non-local goto: commit, rollback or hit the author over the head with a big stick. [Phillip J. Eby] Since this is just a replacement for a try/except/finally block, I'd expect that in a transactional case that a non-local goto would work the same as any other non-exception exit. ISTM that the resource block use cases are: * Save the current state of something, modify it, and then restore the old state once the block completes (try/finally, used for locking, redirection, signals, decimal context, etc.) * Automatically roll back partially-done work in case of exception, and/or roll forward completed work (try/except/else, used for transaction scenarios) * Release allocated resource(s) after use (try/finally, used to close files and suchlike) None of these, AFAICT, benefit from differing behavior in the presence of nonlinear (but non-exceptional) control flow. It just seems too magical to me in the new context. When we were talking about a block construct or user-defined syntax, it made more sense because you could actually redefine the *meaning* of those constructs to some extent -- and because the *target* of the break and continue statements at least was the block itself, not some containing block. That works for me; I was just hypothesizing about the needs of others, but personally I'm fine with not knowing. I guess part of my motivation is also that this information is readily available intenally when a finally-clause is executed, since when the clause completes a pending non-local goto has to be resumed. But there's no reason to expose *all* internal state information... So the signature of __exit__ is just what sys.exc_info() returns. -- --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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
[Steven Bethard] +0. I'm not thoroughly convinced that generators are that much easier to read than a class. But I don't find them hard to read, and I think it would only take a little effort to learn that generators might not always be intended to build iterators. I am proposing (like Phillip Eby in his response to PEP 340) to use a special decorator that turns a generator into a do-template, so the intention is evident from the generator declaration. If we do support generators in do-statements, I'd like their __enter__() and __exit__() methods (if possible) to have semantics like Nick Coghlan suggested[1], so that: * __enter__() raises an exception if next() has already been called, and * __exit__() raises an exception if StopIteration is not raised I guess you missed my post where I gave the code for the decorator; it does exactly that. The simpler semantics give you the difference between a normal exit and an exceptional exit. I'd like to see an example that needs to know the difference between block completion exit and a break/continue/return exit before I'd want to make PEP 340 redux this much more complex. I agreed to that in my response to Phillip Eby. I do want to pass the exception into __exit__ so that it can be logged, for example. -- --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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Guido van Rossum wrote: 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). It seems the effect of Raymond's articles on you was similar to their effect on me :) Straight up-or-down votes in the full senate are appreciated at this point. PEP 340 redux for me (as you might have guessed) - I think the transaction() use case is a genuinely useful one. The ability to access the return value of __enter__() is also more useful than simply duplicating what could be achieved by an assignment on the line before the user defined statement. On to the secondary questions: - Today I like the 'do' keyword better; 'with' might confuse folks coming from Pascal or VB I think 'do' can be made to read correctly in more contexts that 'with'. The lack of a corresponding 'while' or 'until' should eliminate any temptation to see it as a loop. The 'with' keyword also means I keep wanting the magic methods to be called __acquire__ and __release__ (and those would be harder to type. . .) - I have a more elaborate proposal for __exit__'s arguments. Let the translation be as follows: I plan to rewrite my proposal based on this suggestion, just to explore the ramifications. I think it will turn out quite nicely. The ban on yielding inside try/finally will need to be extended to yielding inside user defined statements until such time as an iterator finalisation protocol is chosen, though. (An alternative would be to always call it with 4 arguments, the last three being None in the first two cases.) The former is probably tidier. __exit__() method implementations which don't care about the exception details can still use *exc_info in the argument signature, while those that want to use the information can just name the three parts without needing to specify the =None defaults. Cheers, Nick. -- Nick Coghlan | [EMAIL PROTECTED] | Brisbane, Australia --- http://boredomandlaziness.blogspot.com ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Michael Hudson wrote: 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 same argument could be used (and was probably used) against generators: why not just use __getitem__ and instance state? as soon as you write something longer than four lines, using more than one state variable, you'll find that generator-based code is a lot more readable. /F ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
[Nick Coghlan] The ban on yielding inside try/finally will need to be extended to yielding inside user defined statements until such time as an iterator finalisation protocol is chosen, though. Ah! Good point. This breaks PEP 340 example 5. No big deal, but worth noting. -- --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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Guido van Rossum wrote: 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 Pros: - can use a decorated generator as EXPR - separation of EXPR and VAR (VAR gets what EXPR.__enter__() returns) Cons: - slightly less simple (__enter__ must return something for VAR; __exit__ takes optional args) what happened to the original yield the target object solution? or did I just dream that? /F ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Phillip J. Eby wrote: At 08:41 AM 5/13/2005 -0700, Guido van Rossum wrote: The 'oke' argument is so that the author of transactional() can decide what to do with a non-local goto: commit, rollback or hit the author over the head with a big stick. snip * Automatically roll back partially-done work in case of exception, and/or roll forward completed work (try/except/else, used for transaction scenarios) Doing transactions with try/except/else is not quite correct, since using any of the three non-local goto's actually executes neither the commit nor the rollback (of course, this is where Guido's stick comment comes into play. . .). However, I'm fine with declaring that, from the perspective of a statement template, 'return', 'break' and 'continue' are all 'non-exceptional exits', and so templates like transaction() are expected to treat them as such. Picking one way and enforcing it by restricting the information seen by __exit__() also seems to be a much better option than allowing the possibility of: do bobs.transaction(): break # Triggers a rollback! do alices.transaction(): break # Triggers a commit! Going the 'non-exceptional exits' route also saves inventing a pseudo-exception to stand in for the 3 non-local goto statements (such a pseudo-exception would recreate the above behavioural hole, anyway). An exceptional exit can be forced if a non-local goto needs to be executed in response to a failure: class AbortDo(Exception): pass do alices.transaction(): break # Triggers a commit (non-exceptional exit) try: do alices.transaction(): raise AbortDo # Triggers a rollback (exceptional exit) except AbortDo: break Cheers, Nick. -- Nick Coghlan | [EMAIL PROTECTED] | Brisbane, Australia --- http://boredomandlaziness.blogspot.com ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
[Guido van Rossum] Cons: - slightly less simple (__enter__ must return something for VAR; __exit__ takes optional args) [Fredrik Lundh] what happened to the original yield the target object solution? or did I just dream that? Don't worry, that works when you use a generator. It just doesn't work when you're using a class. The do-statement proposal is a bit ambiguous: on the one hand it's not strongly tied to generators, since you can easily write a class with __enter__ and __exit__ methods; on the other hand its essential difference from PEP 310 is that you *can* use a generator, given a suitable decorator. BTW, we need a name for such a decorated generator that only yields once. I propose to call it a degenerator. -- --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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
[Guido van Rossum] 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? [Greg Ewing] I can't see how this has anything to do with whether a generator is used or not. Keeping them separate seems to be a useful thing in its own right. Assuming by them you mean the value of EXPR and the value assigned to VAR, I don't care how this conclusion is reached, as long as their separation is seen as a useful thing. :-) I came up with the idea of making them separate when I tried to figure out how to decorate a generator to drive a PEP-310-style with-statement, and found I couldn't do it for the opening() example. (Michael Hudson illustrated this nicely in his reply in this thread. :-) But it's fine if the separation is considered generally useful even without thinking of generators. -- --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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Here's my vote on things at the moment: +1 on do EXPR as VAR: ... +1 on keeping the EXPR and VAR distinct. +1 on keeping the do and generator protocols distinct. +1 on not going out of our way to let the controller catch exceptions or alter control flow. Let's keep it as simple as we can. -0.7 on directly giving generators do-protocol methods. I'm not yet convinced that encouraging people to use generators to implement block controllers is a good idea. If we blur the distinction too much at this stage, we may regret it later if we come up with a better idea. Also I don't see that people will be writing block controllers anywhere near as often as iterators, so writing classes for them isn't going to be a big chore. And people can always use a do-protocol-to-generator adaptor if they really want. Greg ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Guido van Rossum wrote: BTW, we need a name for such a decorated generator that only yields once. I propose to call it a degenerator. Cute, but 'template generator' may be clearer (that's what I've been calling them so far, anyway). Then 'iterator generator' can be used to explicitly refer to generators intended for use in for loops. Cheers, Nick. -- Nick Coghlan | [EMAIL PROTECTED] | Brisbane, Australia --- http://boredomandlaziness.blogspot.com ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
[Greg Ewing] -0.7 on directly giving generators do-protocol methods. I'm -1 on this myself. I'm not yet convinced that encouraging people to use generators to implement block controllers is a good idea. If we blur the distinction too much at this stage, we may regret it later if we come up with a better idea. Also I don't see that people will be writing block controllers anywhere near as often as iterators, so writing classes for them isn't going to be a big chore. And people can always use a do-protocol-to-generator adaptor if they really want. Right. I'm +0 on adding a standard module defining a do_template decorator that turns a degenerate generator into a do-statement controller. -- --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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
On 5/11/05, Guido van Rossum [EMAIL PROTECTED] wrote: I realize that the pushback was against looping, but whereas in the PEP 340 proposal general exception handling comes out naturally, it feels as an ugly wart in the modified PEP 310 proposal. Plus I think the use cases are much weaker (even PEP 340 doesn't have many use cases for exception handling -- the only one is the auto-retry example). Accepted, but I still feel that the templates should explicitly include the try...finally, rather than simply having the yield mark the split. The examples seem more readable that way. Explicit is better than implicit, and all that... Paul. ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
On Wed, 11 May 2005, Guido van Rossum wrote: [Steven Bethard] exc = () try: try: BLOCK1 except: exc = sys.exc_info() finally: stmt_exit(*exc) would this make any of the examples impossible to write? All you have to do to suppress an exception is to not reraise it in __exit__. But this use case would contain a trap for the unwary user who is writing an __exit__ method -- they have to remember to re-raise an exception if it was passed in, but that's easy to forget (and slightly tricky since you have to check the arg count or whether the first argument is not None). Then wouldn't it be simplest to separate normal exit from exceptional exit? That is, split __exit__ into __except__ and __finally__. If __except__ is defined, then it handles the exception, otherwise the exception is raised normally. class locking: def __init__(self, lock): self.lock = lock def __enter__(self): self.lock.acquire() def __exit__(self, *args): self.lock.release() Having __exit__ take varargs is a signal to me that it mashes together what really are two different methods. -- ?!ng ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Steven Bethard wrote: On 5/11/05, Nick Coghlan [EMAIL PROTECTED] wrote: The gist is that the alternative is to require an __exit__() method to raise TerminateBlock in order to suppress an exception. So I didn't see any examples that really needed TerminateBlock to suppress an exception. Yeah, I figured out a tidier way to handle it after reading Phillip's message earlier today. My idea is similar to your second solution, but with an early exit via break, continue or return still indicated to the __exit__() method via TerminateBlock so that examples like transaction() continue to do the right thing: the_stmt = EXPR1 stmt_enter = getattr(the_stmt, __enter__, None) stmt_exit = getattr(the_stmt, __exit__, None) if stmt_enter is None or stmt_exit is None: raise TypeError(User defined statement template required) terminate = True VAR1 = stmt_enter() # Omit 'VAR1 =' if no 'as' clause try: try: BLOCK1 except TerminateBlock: raise # Disallow suppression of TerminateBlock except: terminate = False if not stmt_exit(*sys.exc_info()): raise else: terminate = False stmt_exit() finally: if terminate: try: stmt_exit(TerminateBlock, None, None) except TerminateBlock: pass Version 1.5 uses these updated semantics, and the suggested generator __exit__() method semantics are adjusted appropriately. I've also added a paragraph in Open Issues about removing the ability to suppress exceptions as Guido has suggested. However, I'm hoping his objections are based on the assorted horrible mechanisms I used in versions before this one - he is quite right that forcing every __exit__() method to reraise exceptions was a rather ugly wart. The new version also fixes a typo in the auto_retry example that a couple of people pointed out, and adds a non-exception related example from Arnold deVos. The URL is the same as before: http://members.iinet.net.au/~ncoghlan/public/pep-3XX.html Cheers, Nick. -- Nick Coghlan | [EMAIL PROTECTED] | Brisbane, Australia --- http://boredomandlaziness.blogspot.com ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
A quick response to various small issues... - Benji York proposes that file and lock objects (for example) could have suitable __enter__ and __exit__ methods (__enter__ would have to return self). Right! - Greg Ewing (I believe) wants 'do' instead of 'with' for the keyword. I think I like 'with' better, especially combining it with Benji's proposal. IMO this reads better with 'with' than with 'do': with open(/etc/passwd) as f: for line in f: ... - Steve Bethard has this example: stmt = EXPR1 VAR1 = stmt.__enter__() exc = () # or (None, None, None) if you prefer try: try: BLOCK1 except: exc = sys.exc_info() finally: if stmt.__exit__(*exc) is not None: raise exc[0], exc[1], exc[2] but he seems to forget that finally *always* re-raises the exception. Anyway, I still don't care for the use case; rather than fixing the coding bug, your time would be better spent arguing why this functionality can't be missed. - Eric Nieuwland asks if the VAR is still optional. Yes, it is (this is implicit in the entire set of threads). - Paul Moore wants the generator templates to explicitly contain try/finally (or try/except, depending on the use case). That's much more work though (passing exceptions into a generator is a new feature) and is not necessary to get the redux version. - Ka-ping Yee thinks we need separate entry points for the exceptional and the normal termination case. I disagree; this would end up in unnecessary duplication of code (or boilerplate to equate the two methods) in most cases. The whole *point* is that finally gets to do its clean-up act regardless of whether an exception is being processed or not. The varargs signature to __exit__ was just me being lazy instead of typing def __exit__(self, t=None, v=None, tb=None): ... - Nick is still peddling his much more complicated variant. I recommend that he focuses on arguing use cases rather than semantic subtleties, or else it won't get any traction (at least not with me :-). --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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
I think this is my first post to python-dev, so a mini-intro: I've been lurking here for about 5 years, professional user a bit longer, now working at Zope Corp. Guido van Rossum wrote: Going for all-out simplicity, I would like to be able to write these examples: class locking: def __init__(self, lock): self.lock = lock def __enter__(self): self.lock.acquire() def __exit__(self, *args): self.lock.release() class opening: def __init__(self, filename): self.filename = filename def __enter__(self): self.f = open(self.filename); return self.f def __exit__(self, *args): self.f.close() I've read the entire discussion, but may have missed this point, so, correct me if I'm wrong. Wouldn't these semantics let normal objects be used in a do. For example, if the file object had these methods: def __enter__(self): return self def __exit__(self, *args): self.close() you could write do file('whatever) as f: lines = f.readlines() Or a lock: def __enter__(self): self.aquire(); return self def __exit__(self, *args): self.release() do my_lock: a() b() c() -- Benji York Sr. Software Engineer Zope Corporation ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
On 5/12/05, Benji York [EMAIL PROTECTED] wrote: if the file object had these methods: def __enter__(self): return self def __exit__(self, *args): self.close() you could write do file('whatever) as f: lines = f.readlines() Or a lock: def __enter__(self): self.aquire(); return self def __exit__(self, *args): self.release() do my_lock: a() b() c() Ah, finally a proposal that I can understand! But maybe the keyword should be let: let lock: do_something let open(myfile) as f: for line in f: do_something(line) or even, without need of as: let f=file(myfile) : for line in f: do_something(line) which I actually like more Michele Simionato ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Guido van Rossum wrote: Going for all-out simplicity, I would like to be able to write these examples: class locking: def __init__(self, lock): self.lock = lock def __enter__(self): self.lock.acquire() def __exit__(self, *args): self.lock.release() class opening: def __init__(self, filename): self.filename = filename def __enter__(self): self.f = open(self.filename); return self.f def __exit__(self, *args): self.f.close()\ And do EXPR as VAR: BLOCK would mentally be translated into itr = EXPR VAR = itr.__enter__() try: BLOCK finally: itr.__exit__(*sys.exc_info()) # Except sys.exc_info() isn't defined by finally If it's this simple, it should be possible to write something that combines the acquisition of multiple resources in a single statement. For example: with combining(opening(src_fn), opening(dst_fn, 'w')) as src, dst: copy(src, dst) I think the following class would do it. class combining: def __init__(self, *resources): self.resources = resources self.entered = 0 def __enter__(self): results = [] try: for r in self.resources: results.append(r.__enter__()) self.entered += 1 return results except: # exit resources before re-raising the exception self.__exit__() raise def __exit__(self, *args): last_exc = None # exit only the resources successfully entered to_exit = self.resources[:self.entered] while to_exit: r = to_exit.pop() try: r.__exit__(*args) except: # re-raise the exception after exiting the others last_exc = sys.exc_info() if last_exc is not None: raise last_exc[0], last_exc[1], last_exc[2] Would that work? Shane ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
[Shane Hathaway] If it's this simple, it should be possible to write something that combines the acquisition of multiple resources in a single statement. For example: with combining(opening(src_fn), opening(dst_fn, 'w')) as src, dst: copy(src, dst) Yeah (and I don't see anything wrong with your implementation of combining either), but even if that existed I think I'd prefer to just write with opening(src_fn) as src: with opening(dst_fn) as dst: copy(src, dst) See Ma, no magic! :-) -- --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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Guido van Rossum wrote: - Greg Ewing (I believe) wants 'do' instead of 'with' for the keyword. I think I like 'with' better, especially combining it with Benji's proposal. IMO this reads better with 'with' than with 'do': with open(/etc/passwd) as f: for line in f: ... I don't think I like the idea of giving the file object itself __enter__ and __exit__ methods, because it doesn't ensure that the opening and closing are done as a pair. It would permit the following kind of mistake: f = open(somefile) with f: do_something() with f: do_something_else() which our proposed construct, if it is any good, should be able to prevent. Also I don't at all agree that with open(...) reads better; on the contrary, it seems ungrammatical. Especially when compared with the very beautiful do opening(...), which I would be disappointed to give up. I still also have reservations about with on the grounds that we're making it mean something very different to what it means in most other languages that have a with. -- Greg Ewing, Computer Science Dept, +--+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | [EMAIL PROTECTED] +--+ ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Michele Simionato wrote: let lock: do_something let open(myfile) as f: for line in f: do_something(line) This is getting even further into the realm of gibberish to my ear. let f=file(myfile) : for line in f: do_something(line) To anyone with a Lisp or funcional background, that looks like nothing more than a local variable binding. -- Greg Ewing, Computer Science Dept, +--+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | [EMAIL PROTECTED] +--+ ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Phillip J. Eby wrote: Of course, it's not *really* that simple, because __try__ doesn't exactly correspond to 'try:', and it has to return something, but it sure is simpler than the mental gymnastics I'd go through to convert except/else/finally into if statements inside an __exit__. You don't need to make that translation, though. Instead, you can just reraise the passed in exception inside the __exit__() method: def __exit__(self, *exc_info): try: try: if exc_info: raise exc_info[0], exc_info[1], exc_info[2] except: pass else: pass finally: pass However, the __exit__() method does allow you to switch to using if statements if that makes more sense (or would be more efficient). For instance, these are possible __exit__ methods for a locking() statement template and a transaction() statement template: # locking's exit method def __exit__(self, *exc_info): self.lock.release() if exc_info: raise exc_info[0], exc_info[1], exc_info[2] # transaction's exit method def __exit__(self, *exc_info): if exc_info: self.db.rollback() raise exc_info[0], exc_info[1], exc_info[2] else: self.db.commit() I've posted draft 1.4 of my PEP 310/PEP 340 merger PEP (PEP 650, maybe?): http://members.iinet.net.au/~ncoghlan/public/pep-3XX.html This version cleans up the semantics a lot, so that the examples actually work as intended, and there is One Obvious Way to do things like suppressing exceptions (i.e. don't reraise them in the __exit__() method). It also specifically addresses the question of using two methods in the protocol versus four, and shows how an arbitrary try statement can be converted to a statement template. Cheers, Nick. -- Nick Coghlan | [EMAIL PROTECTED] | Brisbane, Australia --- http://boredomandlaziness.blogspot.com ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
On 5/11/05, Nick Coghlan [EMAIL PROTECTED] wrote: I've posted draft 1.4 of my PEP 310/PEP 340 merger PEP (PEP 650, maybe?): http://members.iinet.net.au/~ncoghlan/public/pep-3XX.html I've been skipping the discussion, but this is starting to look pretty good. I'll give it a proper read soon. However, one thing immediately struck me: if __exit__ gets an exception and does not re-raise it, it is silently ignored. This seems like a bad idea - the usual errors should not pass silently applies. I can very easily imagine statement templates accidentally eating KeyboardInterrupt or SystemExit exceptions. At the very least, there should be a section in rejected alternatives explaining why it is not appropriate to force reraising of exceptions unless explicit action is taken. There could be good reasons (as I say, I haven't followed the discussion) but they should be recorded. And if there aren't any good reasons, this behaviour should probably be changed. Paul. PS Apologies if I missed the discussion of this in the PEP - as I say, I've only skimmed it so far. ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
[Guido] Now it would make more sense to change the syntax to with EXPR as VAR: BLOCK and we have Phillip Eby's proposal. [Greg] Change the 'with' to 'do' and I'd be +1 on this. Great! But the devil is in the details. I want to reduce the complexity, and I'm willing to reduce the functionality somewhat. It would help if you could support this. In particular, while I like the use case transactional() (example 3 in PEP 340) enough to want some indicator of success or failure, I don't see the point of having separate __except__, __else__ and __finally__ entry points. It's unclear how these would be mapped to the generator API, and whether more than one could be called e.g. what if __else__ raises an exception itself -- will __finally__ be called? I'm sure that could be specified rigorously, but I'm not so sure that it is going to be useful and clear. I see several possible levels of information that could be passed to the __exit__ call: (1) None. This is insufficient for the transactional() use case. (2) Only a bool indicating success or failure. This is sufficient for the transactional() use case. (3) Full exception information, with the understanding that when __exit__() returns normally, exception processing will resume as usual (i.e. __exit__() is called from a finally clause). Exceptions raised from __exit__() are considered errors/bugs in __exit__() and should be avoided by robust __exit__() methods. (4) Like (3), but also distinguish between non-local gotos (break/continue/return), exceptions, and normal completion of BLOCK. (I'm not sure that this is really different from (3).) What do you think? -- --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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
[Phillip J. Eby] FYI, there are still use cases for clearing the exception state in an __exit__ method, that might justify allowing a true return from __exit__ to suppress the error. e.g.: [...] Yes, but aren't those written clearer using an explicit try/except? IMO anything that actually stops an exception from propagating outward is worth an explicit try/except clause, so the reader knows what is happening. -- --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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
At 10:42 AM 5/11/2005 -0700, Guido van Rossum wrote: [Phillip J. Eby] FYI, there are still use cases for clearing the exception state in an __exit__ method, that might justify allowing a true return from __exit__ to suppress the error. e.g.: [...] Yes, but aren't those written clearer using an explicit try/except? IMO anything that actually stops an exception from propagating outward is worth an explicit try/except clause, so the reader knows what is happening. I thought the whole point of PEP 340 was to allow abstraction and reuse of patterns that currently use try blocks, including except as well as finally. So, if you're only going to allow try/finally abstraction, wouldn't it make more sense to call it __finally__ instead of __exit__? That would make it clearer that this is purely for try/finally patterns, and not error handling patterns. As for whether they're written more clearly using an explicit try/except, I don't know. Couldn't you say exactly the same thing about explicit try/finally? For that matter, if you used function calls, doesn't it produce the same issue, e.g.: def retry(count,exc_type=Exception): def attempt(func): try: func() except exc_type: pass for i in range(count-1): yield attempt yield lambda f: f() for attempt in retry(3): attempt(somethingThatMightFail) Is this bad style too? ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
[Phillip J. Eby] FYI, there are still use cases for clearing the exception state in an __exit__ method, that might justify allowing a true return from __exit__ to suppress the error. e.g.: [...] [Guido] Yes, but aren't those written clearer using an explicit try/except? IMO anything that actually stops an exception from propagating outward is worth an explicit try/except clause, so the reader knows what is happening. [Phillip] I thought the whole point of PEP 340 was to allow abstraction and reuse of patterns that currently use try blocks, including except as well as finally. Indeed it was. But I'm getting a lot of pushback on the PEP so I'm exploring a simpler proposal with a more limited use case -- that of PEP 310, basically. Note that generators written for this new proposal do not contain try/finally or try/except (and don't need it); they simply contain some actions before the yield and some actions after it, and the with/do/block/stmt statement takes care of calling it. So, if you're only going to allow try/finally abstraction, wouldn't it make more sense to call it __finally__ instead of __exit__? That would make it clearer that this is purely for try/finally patterns, and not error handling patterns. I don't think the name matteres that much; __exit__ doesn't particularly mean error handling to me. I think PEP 310 proposed __enter__ and __exit__ and I was just following that; I've also thought of __enter__/__leave__ or even the nostalgic __begin__/__end__. As for whether they're written more clearly using an explicit try/except, I don't know. Couldn't you say exactly the same thing about explicit try/finally? For try/finally we have a large body of use cases that just scream for abstraction. I'm not convinced that we have the same for try/except. Maybe the key is this: with try/finally, the control flow is unaffected whether the finally clause is present or not, so hiding it from view doesn't matter much for understanding the code; in fact in my mind when I see a try/finally clause I mentally translate it to something that says that resource is held for the duration of this block so I can stop thinking about the details of releasing that resource. try/except, on the other hand, generally changes the control flow, and there is much more variety in the except clause. I don't think the need for abstraction is the same. For that matter, if you used function calls, doesn't it produce the same issue, e.g.: def retry(count,exc_type=Exception): def attempt(func): try: func() except exc_type: pass for i in range(count-1): yield attempt yield lambda f: f() for attempt in retry(3): attempt(somethingThatMightFail) Is this bad style too? Yes (not to mention that the retry def is unreadable and that the 'attempt' callable feels magical). There are many ways of coding retry loops and seeing the bottom two lines (the use) in isolation doesn't give me an idea of what happens when the 3rd attempt fails. Here, EIBTI. -- --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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Phillip J. Eby wrote: FYI, there are still use cases for clearing the exception state in an __exit__ method, that might justify allowing a true return from __exit__ to suppress the error. e.g.: Maybe __exit__ could suppress exceptions using a new idiom: def __exit__(self,*exc): if exc and not last and issubclass(exc[0],self.type): # suppress the exception raise None This seems clearer than return True. Shane ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
At 12:44 PM 5/11/2005 -0600, Shane Hathaway wrote: Phillip J. Eby wrote: FYI, there are still use cases for clearing the exception state in an __exit__ method, that might justify allowing a true return from __exit__ to suppress the error. e.g.: Maybe __exit__ could suppress exceptions using a new idiom: def __exit__(self,*exc): if exc and not last and issubclass(exc[0],self.type): # suppress the exception raise None This seems clearer than return True. Nice, although perhaps a little too cute. But it's moot as Guido has vetoed the whole idea. ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Paul Moore wrote: At the very least, there should be a section in rejected alternatives explaining why it is not appropriate to force reraising of exceptions unless explicit action is taken. There could be good reasons (as I say, I haven't followed the discussion) but they should be recorded. And if there aren't any good reasons, this behaviour should probably be changed. This is a good point - it's one of the things I changed in the simplification of the semantics between 1.3 and 1.4 (previously the behaviour was much as you describe). The gist is that the alternative is to require an __exit__() method to raise TerminateBlock in order to suppress an exception. Then the call to __exit__() in the except clause needs to be wrapped in a try/except TerminateBlock/else, with the else reraising the exception, and the except clause suppressing it. The try/except around BLOCK1 has to have a clause added to reraise TerminateBlock so that it isn't inadvertently suppressed when it is raised by user code (although that may be a feature, not a bug! - I'll have to think about that one) Basically, it's possible to set it up that way, but it was a little ugly and hard to explain. It's suppressed if you don't reraise it is very simple, but makes it easier (too easy?) to inadvertently suppress exceptions. If people are comfortable with a little extra ugliness in the semantic details of 'do' statements in order to make it easier to write correct __exit__() methods, then I'm happy to change it back (I think I just talked myself into doing that, actually). Cheers, Nick. -- Nick Coghlan | [EMAIL PROTECTED] | Brisbane, Australia --- http://boredomandlaziness.blogspot.com ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Paul Moore wrote: PS Apologies if I missed the discussion of this in the PEP - as I say, I've only skimmed it so far. With Guido's latest comments, it looks like this is going to be going into the Open Issues section - his current inclination is that do statements should only abstract finally clauses, not arbitrary exception handling. I believe he's misinterpreting the cause of the pushback against PEP 340 (I think it was the looping that was found objectionable, not the ability to suppress exceptions), but *shrug* :) Cheers, Nick. -- Nick Coghlan | [EMAIL PROTECTED] | Brisbane, Australia --- http://boredomandlaziness.blogspot.com ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
[Nick Coghlan] With Guido's latest comments, it looks like this is going to be going into the Open Issues section - his current inclination is that do statements should only abstract finally clauses, not arbitrary exception handling. I believe he's misinterpreting the cause of the pushback against PEP 340 (I think it was the looping that was found objectionable, not the ability to suppress exceptions), but *shrug* :) I realize that the pushback was against looping, but whereas in the PEP 340 proposal general exception handling comes out naturally, it feels as an ugly wart in the modified PEP 310 proposal. Plus I think the use cases are much weaker (even PEP 340 doesn't have many use cases for exception handling -- the only one is the auto-retry example). -- --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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
On 5/11/05, Nick Coghlan [EMAIL PROTECTED] wrote: The gist is that the alternative is to require an __exit__() method to raise TerminateBlock in order to suppress an exception. So I didn't see any examples that really needed TerminateBlock to suppress an exception. If the semantics of a do-statement was simply: stmt = EXPR1 try: stmt_enter = stmt.__enter__ stmt_exit = stmt.__exit__ except AttributeError: raise TypeError(User defined statement template required) VAR1 = stmt_enter() # Omit 'VAR1 =' if no 'as' clause exc = () try: try: BLOCK1 except: exc = sys.exc_info() finally: stmt_exit(*exc) would this make any of the examples impossible to write? All you have to do to suppress an exception is to not reraise it in __exit__. These semantics would make a normally completed BLOCK1 look like a BLOCK1 exited through return, break or continue, but do we have any use cases that actually need this distinction? I couldn't see any, but I've been reading *way* too many PEP 310/340 posts so probably my eyes are just tired. ;-) If you want the default to be that the exception gets re-raised (instead of being suppressed as it is above), I think you could just change the finally block to something like: finally: if stmt_exit(*exc): raise exc[0], exc[1], exc[2] That would mean that if any nonzero object was returned from __exit__, the exception would be reraised. But, like I say, I've been reading this thread way too much, so I'm probably just missing the TerminateBlock use cases. =) STeVe -- You can wordify anything if you just verb it. --- Bucky Katt, Get Fuzzy ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
On 5/11/05, Steven Bethard [EMAIL PROTECTED] wrote: If you want the default to be that the exception gets re-raised (instead of being suppressed as it is above), I think you could just change the finally block to something like: finally: if stmt_exit(*exc): raise exc[0], exc[1], exc[2] That would mean that if any nonzero object was returned from __exit__, the exception would be reraised. Oops. This should have been: finally: if not stmt_exit(*exc): raise exc[0], exc[1], exc[2] This would mean that if a function returned None (or any other False object) the exception would be reraised. Suppressing the reraising of the exception would require returning a nonzero object. STeVe -- You can wordify anything if you just verb it. --- Bucky Katt, Get Fuzzy ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
[Steven Bethard] So I didn't see any examples that really needed TerminateBlock to suppress an exception. If the semantics of a do-statement was simply: stmt = EXPR1 try: stmt_enter = stmt.__enter__ stmt_exit = stmt.__exit__ except AttributeError: raise TypeError(User defined statement template required) VAR1 = stmt_enter() # Omit 'VAR1 =' if no 'as' clause exc = () try: try: BLOCK1 except: exc = sys.exc_info() finally: stmt_exit(*exc) would this make any of the examples impossible to write? All you have to do to suppress an exception is to not reraise it in __exit__. But this use case would contain a trap for the unwary user who is writing an __exit__ method -- they have to remember to re-raise an exception if it was passed in, but that's easy to forget (and slightly tricky since you have to check the arg count or whether the first argument is not None). Going for all-out simplicity, I would like to be able to write these examples: class locking: def __init__(self, lock): self.lock = lock def __enter__(self): self.lock.acquire() def __exit__(self, *args): self.lock.release() class opening: def __init__(self, filename): self.filename = filename def __enter__(self): self.f = open(self.filename); return self.f def __exit__(self, *args): self.f.close()\ And do EXPR as VAR: BLOCK would mentally be translated into itr = EXPR VAR = itr.__enter__() try: BLOCK finally: itr.__exit__(*sys.exc_info()) # Except sys.exc_info() isn't defined by finally -- --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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
[Guido] Going for all-out simplicity, I would like to be able to write these examples: class locking: def __init__(self, lock): self.lock = lock def __enter__(self): self.lock.acquire() def __exit__(self, *args): self.lock.release() class opening: def __init__(self, filename): self.filename = filename def __enter__(self): self.f = open(self.filename); return self.f def __exit__(self, *args): self.f.close()\ And do EXPR as VAR: BLOCK would mentally be translated into itr = EXPR VAR = itr.__enter__() try: BLOCK finally: itr.__exit__(*sys.exc_info()) # Except sys.exc_info() isn't defined by finally Yeah, that's what I wanted to do too. That should be about what my second suggestion did. Slightly updated, it looks like: stmt = EXPR1 VAR1 = stmt.__enter__() exc = () # or (None, None, None) if you prefer try: try: BLOCK1 except: exc = sys.exc_info() finally: if stmt.__exit__(*exc) is not None: raise exc[0], exc[1], exc[2] The only difference should be that with the above semantics if you return a (non-None) value from __exit__, the exception will be suppressed (that is, it will not be reraised). Means that if you want to suppress an exception, you have to add a return statement (but if you want exceptions to be reraised, you don't have to do anything.) I suggest this only because there were a few suggested use-cases for suppressing exceptions. OTOH, almost all my uses are just try/finally's so I'm certainly not going to cry if that last finally instead looks like: finally: stmt.__exit__(*exc) raise exc[0], exc[1], exc[2] =) STeVe -- You can wordify anything if you just verb it. --- Bucky Katt, Get Fuzzy ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Guido van Rossum wrote: class locking: def __init__(self, lock): self.lock = lock def __enter__(self): self.lock.acquire() def __exit__(self, *args): self.lock.release() class opening: def __init__(self, filename): self.filename = filename def __enter__(self): self.f = open(self.filename); return self.f def __exit__(self, *args): self.f.close()\ And do EXPR as VAR: BLOCK would mentally be translated into itr = EXPR VAR = itr.__enter__() try: BLOCK finally: itr.__exit__(*sys.exc_info()) # Except sys.exc_info() isn't defined by finally In this example locking's __enter__ does not return anything. Would do EXPR: BLOCK also be legal syntax? -eric ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
On May 9, 2005, at 21:58, Guido van Rossum wrote: Apologies if this has been discovered and rejected already; I've had to skip most of the discussions but this though won't leave my head... Skimming rather than skipping all of the discussion burned most of my py-dev time, and it was just skimming, but I don't remember such rejections. But what if we changed the translation slightly so that VAR gets assigned to value of the __enter__() call: abc = EXPR VAR = abc.__enter__() # I don't see why it should be optional try: BLOCK finally: abc.__exit__() Now it would make more sense to change the syntax to with EXPR as VAR: BLOCK and we have Phillip Eby's proposal. The advantage of this is that you I like this. The only aspect of other proposals that I would sorely miss here, would be the inability for abc.__exit__ to deal with exceptions raised in BLOCK (or, even better, a separate specialmethod on abc called in lieu of __exit__ upon exceptions). Or am I missing something, and would this give a way within abc.__exit__ to examine and possibly ``unraise'' such an exception...? can write a relatively straightforward decorator, call it @with_template, that endows a generator with the __enter__ and __exit__ methods, so you can write all the examples (except auto_retry(), which was there mostly to make a point) from PEP 340 like this: @with_template def opening(filename, mode=r): f = open(filename, mode) yield f f.close() and so on. (Note the absence of a try/finally block in the generator -- the try/finally is guaranteed by the with-statement but not by the generator framework.) I must be thick this morning, because this relatively straightforward decorator isn't immediately obvious to me -- care to show me how with_template gets coded? Alex ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
At 07:57 AM 5/10/2005 -0700, Alex Martelli wrote: On May 9, 2005, at 21:58, Guido van Rossum wrote: But what if we changed the translation slightly so that VAR gets assigned to value of the __enter__() call: abc = EXPR VAR = abc.__enter__() # I don't see why it should be optional try: BLOCK finally: abc.__exit__() Now it would make more sense to change the syntax to with EXPR as VAR: BLOCK and we have Phillip Eby's proposal. The advantage of this is that you I like this. The only aspect of other proposals that I would sorely miss here, would be the inability for abc.__exit__ to deal with exceptions raised in BLOCK (or, even better, a separate specialmethod on abc called in lieu of __exit__ upon exceptions). Or am I missing something, and would this give a way within abc.__exit__ to examine and possibly ``unraise'' such an exception...? Yeah, I'd ideally like to see __try__, __except__, __else__, and __finally__ methods, matching the respective semantics of those clauses in a try/except/finally block. can write a relatively straightforward decorator, call it @with_template, that endows a generator with the __enter__ and __exit__ methods, so you can write all the examples (except auto_retry(), which was there mostly to make a point) from PEP 340 like this: @with_template def opening(filename, mode=r): f = open(filename, mode) yield f f.close() and so on. (Note the absence of a try/finally block in the generator -- the try/finally is guaranteed by the with-statement but not by the generator framework.) I must be thick this morning, because this relatively straightforward decorator isn't immediately obvious to me -- care to show me how with_template gets coded? Something like this, I guess: def with_template(f): class controller(object): def __init__(self,*args,**kw): self.iter = f(*args,**kw) def __enter__(self): return self.iter.next() def __exit__(self): self.iter.next() return controller But I'd rather see it with __try__/__except__ and passing exceptions into the generator so that the generator can use try/except/finally blocks to act on the control flow. ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
[Alex] I like this. The only aspect of other proposals that I would sorely miss here, would be the inability for abc.__exit__ to deal with exceptions raised in BLOCK (or, even better, a separate specialmethod on abc called in lieu of __exit__ upon exceptions). Or am I missing something, and would this give a way within abc.__exit__ to examine and possibly ``unraise'' such an exception...? See my followup to Nick. I'm not worried about unraising exceptions. The only way to mess with the exception from code in a finally-suite is to raise another exception, and we can't really prevent that. However (I forgot this in the response to Nick) unless/until we augment generators in some way the generator can't easily see the exception flag. [me] can write a relatively straightforward decorator, call it @with_template, that endows a generator with the __enter__ and __exit__ methods, so you can write all the examples (except auto_retry(), which was there mostly to make a point) from PEP 340 like this: @with_template def opening(filename, mode=r): f = open(filename, mode) yield f f.close() and so on. (Note the absence of a try/finally block in the generator -- the try/finally is guaranteed by the with-statement but not by the generator framework.) [Alex] I must be thick this morning, because this relatively straightforward decorator isn't immediately obvious to me -- care to show me how with_template gets coded? Here's a sketch: class Wrapper(object): def __init__(self, gen): self.gen = gen self.state = initial def __enter__(self): assert self.state == initial self.state = entered try: return self.gen.next() except StopIteration: self.state = error raise RuntimeError(template generator didn't yield) def __exit__(self): assert self.state == entered self.state = exited try: self.gen.next() except StopIteration: return else: self.state = error raise RuntimeError(template generator didn't stop) def with_template(func): def helper(*args, **kwds): return Wrapper(func(*args, **kwds)) return helper @with_template def opening(filename, mode=r): f = open(filename) # Note that IOError here is untouched by Wrapper yield f f.close() # Ditto for errors here (however unlikely) -- --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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Guido van Rossum wrote: I used to dislike this, but the opposition and the proliferation of alternative proposals have made me realize that I'd rather have this (plus continue EXPR which will be moved to a separate PEP once I have some extra time) than most of the other proposals. Draft 1.3 of my PEP 310/PEP 340 merger is now up for public consumption: http://members.iinet.net.au/~ncoghlan/public/pep-3XX.html This is a major rewrite since version 1.2. Significant changes are: - reorder and reword things to emphasise the user defined statements, and their ability to factor out arbitrary try/except/else/finally boilerplate. - use 'do' as the keyword instead of 'stmt' (I have to say, I *really* like the way 'do' looks and reads in all of the examples) - clean up the semantics of user defined statements so as to make manual statement templates as easy to write as those in PEP 310 - give iterator finalisation its own slot, __finish__() (distinct from the __exit__() of statement templates) - define sensible automatic finalisation semantics for iterative loops - fill out the Rejected Options section meaningfully, with justifications for rejecting certain options - makes the PEP more self-contained, with significantly fewer references to PEP 340. These changes try to take into account the feedback I got on the previous drafts, as well as fixing a few problems I noticed myself. Cheers, Nick. -- Nick Coghlan | [EMAIL PROTECTED] | Brisbane, Australia --- http://boredomandlaziness.blogspot.com ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
[Phillip J. Eby] Yeah, I'd ideally like to see __try__, __except__, __else__, and __finally__ methods, matching the respective semantics of those clauses in a try/except/finally block. What's your use case for adding this complexity? I'm going for simple here unless there's a really strong use case. Anyway, a wrapped generator wrapper can't do with all those distinctions unless we augment the generator somehow (continue EXPR would suffice). (Your decorator is equivalent to mine, but I don't like creating a new class each time.) -- --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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Guido van Rossum wrote: [Nick] Is that use case strong enough to require the added complexity? For a transactional wrapper, I can see that __exit__ needs to know about exceptions (though I'm unsure how much detail it needs), but what's the point of being able to tell an exception from a non-local goto (which break, continue and return really are)? The only real reason the statement template can tell the difference is because those non-local goto's all result in TerminateBlock being passed in as the exception (that's why the __exit__ method can't really tell the difference between those statements and the user code raising TerminateBlock, and also why TerminateBlock can't be suppressed by the statement template). As far as use cases go, any case where we want the statement template to be able to manipulate the exception handling requires that this information be passed in to the __exit__() method. The current examples given in the PEP are transaction() and auto_retry(), but others have been suggested over the course of the discussion. One suggestion was for automatically logging exceptions, which requires access to the full state of the current exception. I go into the motivation behind this a bit more in the updated draft I just posted (version 1.3). The basic idea is to allow factoring out of arbitrary try/except/else/finally code into a statement template, and use a 'do' statement to provide the contents of the 'try' clause. If the exception information isn't passed in, then we can really only factor out try/finally statements, which is far less interesting. What's your use case for giving __enter__ an opportunity to skip the block altogether? I realised that I don't have one - so the idea doesn't appear in the updated draft. Regards, Nick. -- Nick Coghlan | [EMAIL PROTECTED] | Brisbane, Australia --- http://boredomandlaziness.blogspot.com ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Nick Coghlan wrote: Draft 1.3 of my PEP 310/PEP 340 merger is now up for public consumption: http://members.iinet.net.au/~ncoghlan/public/pep-3XX.html This draft was meant to drop the idea of __enter__() raising TerminateBlock preventing execution of the statement body. I dropped it out of the code describing the semantics, but the idea is still mentioned in the text. I'll probably do another draft to fix that, and various ReST problems tomorrow night. I'll also add in a justification for why I chose the single __exit__ method over separate __else__, __except__ and __finally__ methods. Cheers, Nick. -- Nick Coghlan | [EMAIL PROTECTED] | Brisbane, Australia --- http://boredomandlaziness.blogspot.com ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
At 08:51 AM 5/10/2005 -0700, Guido van Rossum wrote: [Phillip J. Eby] Yeah, I'd ideally like to see __try__, __except__, __else__, and __finally__ methods, matching the respective semantics of those clauses in a try/except/finally block. What's your use case for adding this complexity? It makes it much easier to mentally translate a given try/except/else/finally usage to a resource or block controller or whatever it is we're calling these things now. You should almost be able to just stick 'def __' and '__(self):' and then munge the whole thing into a class. Of course, it's not *really* that simple, because __try__ doesn't exactly correspond to 'try:', and it has to return something, but it sure is simpler than the mental gymnastics I'd go through to convert except/else/finally into if statements inside an __exit__. Granted, if we end up with __enter__ and __exit__, I'll just write a resource mixin class whose __exit__ calls a stubbed-out __except__, __else__, and __finally__. Then I won't have to figure out how to write __exit__ methods all the time. Which is great for me, but I was thinking that this interface would reduce complexity for people trying to learn how to write these things. I wasn't advocating this before because PEP 340's use of generators allowed you to directly use try/except/else/finally. But, the new approach seems targeted at a wider set of use cases that don't include generators. IOW, it's likely you'll be adding resource-finalization methods to actual resource classes, and grafting generators into them to implement __enter__/__exit__ seems more complex at first glance than just letting people add the methods directly; e.g.: def __enter__(self): self.handler = self._resource_control() return self.handler.__enter__() def __exit__(self): self.handler.__exit__() @with_template def _resource_control(self): f = self.open(blah) try: yield f finally: f.close() versus this rather more obvious way to do it: def __try__(self): self.f = self.open(blah) return self.f def __finally__(self): self.f.close() But I suppose you could encapsulate either pattern as a mixin class, so I suppose this could be treated as a matter for examples in documentation rather than as an implementation aspect. It's just that if __exit__ has to probe exception state or other wizardry, it's going to be harder for non-wizards to use, and that's what I was reacting to here. Anyway, I see now that documentation and simple mixins could address it, so if you think it's best handled that way, so be it. I'm going for simple here unless there's a really strong use case. Anyway, a wrapped generator wrapper can't do with all those distinctions unless we augment the generator somehow (continue EXPR would suffice). You'd use only __try__, __except__, and __else__ to wrap a generator. For some other use cases you'd only use __try__ and __finally__, or __try__ and __except__, or __try__ and __else__. I don't know of any use cases where you'd want to use all four simultaneously on the same controller. (Your decorator is equivalent to mine, but I don't like creating a new class each time.) Mine was just a sketch to show the idea anyway; I'd be surprised if it doesn't have at least one bug. ___ 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
Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?
Guido van Rossum wrote: Now it would make more sense to change the syntax to with EXPR as VAR: BLOCK and we have Phillip Eby's proposal. Change the 'with' to 'do' and I'd be +1 on this. -- Greg Ewing, Computer Science Dept, +--+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | [EMAIL PROTECTED] +--+ ___ 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