Re: [Python-Dev] PEP 463: Exception-catching expressions
On Thu, Mar 13, 2014 at 07:54:18AM +1100, Chris Angelico wrote: On Thu, Mar 13, 2014 at 7:26 AM, Martin v. Löwis mar...@v.loewis.de wrote: I think you (or someone) first needs to find a BDFL delegate. Traditionally, with syntax changes, there is a good chance that Guido doesn't want to delegate at all, so ask him whether he wants to delegate or not. He beat you to it; the PEP has now been rejected. :) Guido said he *wanted* to reject it, and that there would be no more pronouncement until after the language summit. I think you should wait until after the summit before declaring it categorically rejected, perhaps somebody will persuade Guido to change his mind :-) But either way, thanks for tackling this, the threads about syntax were monsterous and I ran out of steam trying to keep up with it all long ago. -- Steven ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Tue Mar 11 2014 at 11:59:23 PM, Chris Angelico ros...@gmail.com wrote: On Wed, Mar 12, 2014 at 2:20 PM, Ethan Furman et...@stoneleaf.us wrote: I sure hope this is accepted. I could have used it at least a half-dozen times in the last week -- which is more often than I would have used the ternary-if! :) Where do we go from here? I've not made any edits for some time - no material edits for a good while - how do I request pronouncement? You start a new email thread asking for pronouncement. Don't be surprised, though, if it is postponed until PyCon since the language summit is 4 weeks away. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
Am 12.03.14 04:58, schrieb Chris Angelico: On Wed, Mar 12, 2014 at 2:20 PM, Ethan Furman et...@stoneleaf.us wrote: I sure hope this is accepted. I could have used it at least a half-dozen times in the last week -- which is more often than I would have used the ternary-if! :) Where do we go from here? I've not made any edits for some time - no material edits for a good while - how do I request pronouncement? I think you (or someone) first needs to find a BDFL delegate. Traditionally, with syntax changes, there is a good chance that Guido doesn't want to delegate at all, so ask him whether he wants to delegate or not. You should also add a section on the implementation status; it's unclear (to me) whether the proposed implementation actually matches the specification. Regards, Martin ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Thu, Mar 13, 2014 at 7:26 AM, Martin v. Löwis mar...@v.loewis.de wrote: I think you (or someone) first needs to find a BDFL delegate. Traditionally, with syntax changes, there is a good chance that Guido doesn't want to delegate at all, so ask him whether he wants to delegate or not. He beat you to it; the PEP has now been rejected. :) You should also add a section on the implementation status; it's unclear (to me) whether the proposed implementation actually matches the specification. Hmm. I left that sort of comment out, partly because both the proposal and the implementation were fluid. I also had a bit of trouble making everything work, and had to submit some more patches. So I'm not sure what would be counted as the reference implementation. ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
I sure hope this is accepted. I could have used it at least a half-dozen times in the last week -- which is more often than I would have used the ternary-if! :) -- ~Ethan~ ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Wed, Mar 12, 2014 at 2:20 PM, Ethan Furman et...@stoneleaf.us wrote: I sure hope this is accepted. I could have used it at least a half-dozen times in the last week -- which is more often than I would have used the ternary-if! :) Where do we go from here? I've not made any edits for some time - no material edits for a good while - how do I request pronouncement? ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Thu, Feb 27, 2014 at 1:29 PM, Chris Angelico ros...@gmail.com wrote: +Had this facility existed early in Python's history, there would have been +no need to create dict.get() and related methods; FWIW, after experimenting and some consideration I've come to the conclusion that this is incorrect. 'd[k] except KeyError: default' is still much broader than dict.get(k): Python 3.4.0rc1+ (default:aa2ae744e701+, Feb 24 2014, 01:22:15) [GCC 4.6.3] on linux Type help, copyright, credits or license for more information. expensive_calculation = hash class C: ... _hash_cache = {} ... def __init__(self, value): ... self.value = value ... if value not in self._hash_cache: ... self._hash_cache[value] = expensive_calculation(value) ... def __hash__(self): ... return self._hash_cache[self.value] ... def __eq__(self, other): ... return self.value == other ... a, b, c, d = C(1), C(2), C(3), C(4) D = {a: 1, b: 2, c: 3, d: 4} a.value = 5 print(except expr:, (D[a] except KeyError: 'default')) except expr: default print(dict.get:, D.get(a, 'default')) Traceback (most recent call last): File stdin, line 1, in module File stdin, line 8, in __hash__ KeyError: 5 All in all I believe I will continue to prefer specific methods for specific use-cases; I'm -0 on the idea of an except-expression, -0 on the syntax with the mandatory parentheses around the whole thing (and so far -1 on any of the other suggested forms.) I can see the attractiveness, but frankly, all the suggested changes to the stdlib fall in two categories: easier to express (and narrower in its exception handling) with e.g. dict.get for the trivial ones, or much better written out using temporary variables for the complex ones. As soon as an except-expression has trouble fitting on two lines it becomes an unsightly mess; it no longer becomes obvious what it does from a glance. Not having except-expr may mean we keep adding methods (with different names, and slightly different semantics) to cover specific use-cases of specific types, but I can live with that. -- Thomas Wouters tho...@python.org Hi! I'm an email virus! Think twice before sending your email to help me spread! ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Thu, Mar 6, 2014 at 7:57 AM, Thomas Wouters tho...@python.org wrote: On Thu, Feb 27, 2014 at 1:29 PM, Chris Angelico ros...@gmail.com wrote: +Had this facility existed early in Python's history, there would have been +no need to create dict.get() and related methods; FWIW, after experimenting and some consideration I've come to the conclusion that this is incorrect. 'd[k] except KeyError: default' is still much broader than dict.get(k): *Much* broader? You prove that it's broader, yes, but most types aren't defining __hash__ methods that can fail with KeyError. Can you show any real-world code that trips this? I'd say the broadened exception scope (or, putting it the other way, the narrowed exception scope of adding dict.get() after except-expressions had already existed) is insufficiently significant to justify adding an extra method to the dict. Since the method does exist, it will continue to be useful, but if except expressions did and dict.get() didn't, there'd have been very little justification for them. And certainly hasattr() wouldn't need to exist, since it exactly _does_ try to get the attribute and see if AttributeError is raised. ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Thu, Mar 6, 2014 at 7:57 AM, Thomas Wouters tho...@python.org wrote: All in all I believe I will continue to prefer specific methods for specific use-cases; I'm -0 on the idea of an except-expression, -0 on the syntax with the mandatory parentheses around the whole thing (and so far -1 on any of the other suggested forms.) I can see the attractiveness, but frankly, all the suggested changes to the stdlib fall in two categories: easier to express (and narrower in its exception handling) with e.g. dict.get for the trivial ones, or much better written out using temporary variables for the complex ones. As soon as an except-expression has trouble fitting on two lines it becomes an unsightly mess; it no longer becomes obvious what it does from a glance. Not having except-expr may mean we keep adding methods (with different names, and slightly different semantics) to cover specific use-cases of specific types, but I can live with that. Most of those concerns could also be aimed at the if/else expression. There are definitely places that do not merit its use, but that doesn't mean the feature is a bad one. The PEP has a number of examples that fit quite happily on a single line, and it's those that I'm advocating. We have comprehensions, genexps, etc, etc, all (or at least most) of which can be written out in some form of long-hand, and it's usually better to use the short-hand - it's not just laziness, it's expressiveness. Speaking of the PEP, if someone could apply the latest changes, I think it's pretty much ready for pronouncement. Thanks! Content: https://raw.github.com/Rosuav/ExceptExpr/master/pep-0463.txt Diff from current peps repo: diff -r 2cf89e9e50a3 pep-0463.txt --- a/pep-0463.txt Tue Mar 04 18:47:44 2014 -0800 +++ b/pep-0463.txt Thu Mar 06 11:12:44 2014 +1100 @@ -250,7 +250,8 @@ alternatives listed above must (by the nature of functions) evaluate their default values eagerly. The preferred form, using the colon, parallels try/except by using except exception_list:, and parallels lambda by having -keyword name_list: subexpression. Using the arrow introduces a token many +keyword name_list: subexpression; it also can be read as mapping Exception +to the default value, dict-style. Using the arrow introduces a token many programmers will not be familiar with, and which currently has no similar meaning, but is otherwise quite readable. The English word pass has a vaguely similar meaning (consider the common usage pass by value/reference @@ -271,6 +272,18 @@ Using the preferred order, subexpressions will always be evaluated from left to right, no matter how the syntax is nested. +Keeping the existing notation, but shifting the mandatory parentheses, we +have the following suggestion:: + +value = expr except (Exception: default) +value = expr except(Exception: default) + +This is reminiscent of a function call, or a dict initializer. The colon +cannot be confused with introducing a suite, but on the other hand, the new +syntax guarantees lazy evaluation, which a dict does not. The potential +to reduce confusion is considered unjustified by the corresponding potential +to increase it. + Example usage = @@ -854,6 +867,32 @@ expression to achieve this. +Common objections += + +Colons always introduce suites +-- + +While it is true that many of Python's syntactic elements use the colon to +introduce a statement suite (if, while, with, for, etcetera), this is not +by any means the sole use of the colon. Currently, Python syntax includes +four cases where a colon introduces a subexpression: + +* dict display - { ... key:value ... } +* slice notation - [start:stop:step] +* function definition - parameter : annotation +* lambda - arg list: return value + +This proposal simply adds a fifth: + +* except-expression - exception list: result + +Style guides and PEP 8 should recommend not having the colon at the end of +a wrapped line, which could potentially look like the introduction of a +suite, but instead advocate wrapping before the exception list, keeping the +colon clearly between two expressions. + + Copyright = ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Wed, Mar 5, 2014 at 4:28 PM, Chris Angelico ros...@gmail.com wrote: On Thu, Mar 6, 2014 at 7:57 AM, Thomas Wouters tho...@python.org wrote: All in all I believe I will continue to prefer specific methods for specific use-cases; I'm -0 on the idea of an except-expression, -0 on the syntax with the mandatory parentheses around the whole thing (and so far -1 on any of the other suggested forms.) I can see the attractiveness, but frankly, all the suggested changes to the stdlib fall in two categories: easier to express (and narrower in its exception handling) with e.g. dict.get for the trivial ones, or much better written out using temporary variables for the complex ones. As soon as an except-expression has trouble fitting on two lines it becomes an unsightly mess; it no longer becomes obvious what it does from a glance. Not having except-expr may mean we keep adding methods (with different names, and slightly different semantics) to cover specific use-cases of specific types, but I can live with that. Most of those concerns could also be aimed at the if/else expression. And I did :) But the if-else expression had a single thing going for it, the thing that landed the actual feature: it prevents people from using buggy alternatives in the quest for short code, the and-or trick. You may remember that Guido initially rejected the if-else expression, until he realized people were going to use something like it whether he liked it or not. The except-expression has a different issue: people catching exceptions too broadly. I don't believe that's as big a problem, nor is it as subtly wrong. And the except-expression doesn't solve _all_ such issues, just a very small subset. It's just another thing to learn when you're new, and just another thing to consider when reviewing code. There are definitely places that do not merit its use, but that doesn't mean the feature is a bad one. The PEP has a number of examples that fit quite happily on a single line, and it's those that I'm advocating. We have comprehensions, genexps, etc, etc, all (or at least most) of which can be written out in some form of long-hand, and it's usually better to use the short-hand - it's not just laziness, it's expressiveness. It's not a question of it being expressive, it's a question of it being worth separate syntax. I don't think it's worth syntax. Speaking of the PEP, if someone could apply the latest changes, I think it's pretty much ready for pronouncement. Thanks! PEP update pushed (changeset 59653081cdf6.) Content: https://raw.github.com/Rosuav/ExceptExpr/master/pep-0463.txt Diff from current peps repo: diff -r 2cf89e9e50a3 pep-0463.txt --- a/pep-0463.txt Tue Mar 04 18:47:44 2014 -0800 +++ b/pep-0463.txt Thu Mar 06 11:12:44 2014 +1100 @@ -250,7 +250,8 @@ alternatives listed above must (by the nature of functions) evaluate their default values eagerly. The preferred form, using the colon, parallels try/except by using except exception_list:, and parallels lambda by having -keyword name_list: subexpression. Using the arrow introduces a token many +keyword name_list: subexpression; it also can be read as mapping Exception +to the default value, dict-style. Using the arrow introduces a token many programmers will not be familiar with, and which currently has no similar meaning, but is otherwise quite readable. The English word pass has a vaguely similar meaning (consider the common usage pass by value/reference @@ -271,6 +272,18 @@ Using the preferred order, subexpressions will always be evaluated from left to right, no matter how the syntax is nested. +Keeping the existing notation, but shifting the mandatory parentheses, we +have the following suggestion:: + +value = expr except (Exception: default) +value = expr except(Exception: default) + +This is reminiscent of a function call, or a dict initializer. The colon +cannot be confused with introducing a suite, but on the other hand, the new +syntax guarantees lazy evaluation, which a dict does not. The potential +to reduce confusion is considered unjustified by the corresponding potential +to increase it. + Example usage = @@ -854,6 +867,32 @@ expression to achieve this. +Common objections += + +Colons always introduce suites +-- + +While it is true that many of Python's syntactic elements use the colon to +introduce a statement suite (if, while, with, for, etcetera), this is not +by any means the sole use of the colon. Currently, Python syntax includes +four cases where a colon introduces a subexpression: + +* dict display - { ... key:value ... } +* slice notation - [start:stop:step] +* function definition - parameter : annotation +* lambda - arg list: return value + +This proposal simply adds a fifth: + +* except-expression - exception list: result + +Style guides and PEP 8 should
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Thu, Mar 6, 2014 at 12:03 PM, Thomas Wouters tho...@python.org wrote: PEP update pushed (changeset 59653081cdf6.) Thanks for that! ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Wed, Mar 05, 2014 at 12:57:03PM -0800, Thomas Wouters wrote: On Thu, Feb 27, 2014 at 1:29 PM, Chris Angelico ros...@gmail.com wrote: +Had this facility existed early in Python's history, there would have been +no need to create dict.get() and related methods; FWIW, after experimenting and some consideration I've come to the conclusion that this is incorrect. 'd[k] except KeyError: default' is still much broader than dict.get(k): I don't think your example proves what you think it does. I think it demonstrates a bug in the dict.get method. The documentation for get states clearly that get will never raise KeyError: Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError. http://docs.python.org/3/library/stdtypes.html#dict.get but your example demonstrates that in fact it can raise KeyError (albeit under some rather unusual circumstances): Python 3.4.0rc1+ (default:aa2ae744e701+, Feb 24 2014, 01:22:15) [GCC 4.6.3] on linux Type help, copyright, credits or license for more information. expensive_calculation = hash class C: ... _hash_cache = {} ... def __init__(self, value): ... self.value = value ... if value not in self._hash_cache: ... self._hash_cache[value] = expensive_calculation(value) ... def __hash__(self): ... return self._hash_cache[self.value] ... def __eq__(self, other): ... return self.value == other ... a, b, c, d = C(1), C(2), C(3), C(4) D = {a: 1, b: 2, c: 3, d: 4} a.value = 5 print(except expr:, (D[a] except KeyError: 'default')) except expr: default print(dict.get:, D.get(a, 'default')) Traceback (most recent call last): File stdin, line 1, in module File stdin, line 8, in __hash__ KeyError: 5 According to the documentation, this behaviour is wrong. Now, you might argue that the documentation is wrong. I'm sympathetic to that argument, but *as documented now*, dict.get is documented as being logically equivalent to: try: return d[key] except KeyError: return default The fact that it actually isn't is an artifact of the specific implementation used. If it were a deliberate design choice, that design is not reflected in the documentation. Whether the current behaviour is wrong, or the documentation is wrong, is irrelevant to the question of whether or not the developers back in nineteen-ninety-whatever would have choosen to add dict.get had there been syntax for catching the KeyError in an expression. Perhaps they would have argued: Sure, you can catch the KeyError yourself, but 'get' is a fundamental operation for mappings, and I think that dict should implement a 'get' method just to be complete. Or perhaps not. Some developers prefer minimalist APIs, some developers prefer more exhaustive APIs. Regardless of what might have happened back in 199x when dict.get was first discussed, I think we can agree that an except expression will lower the pressure on Python to add *more* get-like methods, or add default arguments, in the future. -- Steven ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 3/5/2014 8:15 PM, Steven D'Aprano wrote: On Wed, Mar 05, 2014 at 12:57:03PM -0800, Thomas Wouters wrote: On Thu, Feb 27, 2014 at 1:29 PM, Chris Angelico ros...@gmail.com wrote: +Had this facility existed early in Python's history, there would have been +no need to create dict.get() and related methods; FWIW, after experimenting and some consideration I've come to the conclusion that this is incorrect. 'd[k] except KeyError: default' is still much broader than dict.get(k): I don't think your example proves what you think it does. I think it demonstrates a bug in the dict.get method. The documentation for get states clearly that get will never raise KeyError: Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError. http://docs.python.org/3/library/stdtypes.html#dict.get but your example demonstrates that in fact it can raise KeyError (albeit under some rather unusual circumstances): Python 3.4.0rc1+ (default:aa2ae744e701+, Feb 24 2014, 01:22:15) [GCC 4.6.3] on linux Type help, copyright, credits or license for more information. expensive_calculation = hash class C: ... _hash_cache = {} ... def __init__(self, value): ... self.value = value ... if value not in self._hash_cache: ... self._hash_cache[value] = expensive_calculation(value) ... def __hash__(self): ... return self._hash_cache[self.value] This is a buggy special method. According to the docs for hash and __hash__ and the general convention on exceptions, a __hash__ method should return an int or raise TypeError. ... def __eq__(self, other): ... return self.value == other ... a, b, c, d = C(1), C(2), C(3), C(4) D = {a: 1, b: 2, c: 3, d: 4} a.value = 5 This breaks the implied C invariant and makes the object 'a' incoherent and buggy print(dict.get:, D.get(a, 'default')) Traceback (most recent call last): File stdin, line 1, in module File stdin, line 8, in __hash__ KeyError: 5 According to the documentation, this behaviour is wrong. One could argue that an error raised in a special method is not raised *by* a function that uses the special method. The docs constantly assume that special methods are coded correctly. '''bool([x]) Convert a value to a Boolean, using the standard truth testing procedure. If x is false or omitted, this returns False; otherwise it returns True.''' ... unless x.__bool__ raises or returns something other than True/False -- in which case bool itself raises. TypeError: __bool__ should return bool, returned int Now, you might argue that the documentation is wrong. I'm sympathetic to that argument, but *as documented now*, dict.get is documented as being logically equivalent to: try: return d[key] except KeyError: return default It appears to be actually equivalent to key_hash = hash(key) try: return d._hashlookup(key_has) except KeyError: return default The fact that it actually isn't is an artifact of the specific implementation used. If it were a deliberate design choice, Given that the choice is that bugs in special methods should not pass silently, I would presume that it is intentional. that design is not reflected in the documentation. The docs generally describe behavior in the absence of coding errors. -- Terry Jan Reedy ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
Steven D'Aprano wrote: Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError. I think that's supposed to mean that it won't raise KeyError as a result of the key not being in the dictionary. The actual behaviour is correct, IMO, because it avoids masking bugs, so this could probably be worded better. -- Greg ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Fri, Feb 28, 2014 at 6:38 PM, Glenn Linderman v+pyt...@g.nevcal.com wrote: Whereas the current PEP syntax has ambiguity regarding how to interpret a-expr except except-list-b: b-expr except except-list-c: c-expr (does the 2nd except apply to a-expr or b-expr?), without parentheses, and, as far as I am concerned, even with the parentheses, this syntax makes it very clear that each of the Exception-lists apply to a-expr. Fair enough. It's a bit hard to talk about multiple except expressions, though, as they're a problem unless formally supported - and they're almost never needed. Really, all you need to do is say never abut except-expressions without parentheses (which the current proposal and the parens around the exception bit only proposal both enforce), and then there's no problem. I expect that normal use of this won't include any form of chaining. Yes, it can - like any feature - be used abnormally, but at some point it's better to just drop it out as a statement. Key advantage to others may be that because the : is within the () [and the leading ( is quite nearby, making it obvious], it is less likely to be considered a statement boundary, and more easily explained as a special type of list syntax... not _really_ a list, because it is really code to be executed somewhat sequentially rather than data, and lists don't have : ... and not _really_ a dict constant, which does have :, because the Exception is not _really_ a key, but the syntax can draw on analogies with the dict constant syntax which will help people remember it, and even sort of understand that there is a pair-wise relationship between the Exception-list and the expression after the :, without repeating the except over and over. See the confusing terminology we have here? It might be called a list of except-expressions, but the brackets are round, and a list's are square. It's kinda like dict syntax, only again, the other sort of bracket, and it's wrong to try to construct a dict; it'd be too tempting to conflate this with some of the other current proposals for lazily-evaluated expressions (aka simpler syntax for lambda or other terms). This is, fundamentally, a multi-part expression on par with and and or: first, evaluate the primary expression; then, if an exception is raised, evaluate the exception list and see if it matches; then, if it matches, squash the exception and evaluate the default expression. You can't turn that into a dict, partly because you'd need to sort out lazy evaluation, and partly because a dict is unordered - if this is expanded to support multiple except clauses, they have to be processed in order. (You might, for instance, catch ZeroDivisionError, and then Exception, with different handling. It'd be VERY confusing for them to be processed in the wrong order, particularly if it happens unpredictably.) Are there any other expressions that allow parens around a part of the expression, without the stuff inside them becoming a completely separate sub-expression? ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 2/28/2014 12:41 AM, Chris Angelico wrote: On Fri, Feb 28, 2014 at 6:38 PM, Glenn Linderman v+pyt...@g.nevcal.com wrote: Whereas the current PEP syntax has ambiguity regarding how to interpret a-expr except except-list-b: b-expr except except-list-c: c-expr (does the 2nd except apply to a-expr or b-expr?), without parentheses, and, as far as I am concerned, even with the parentheses, this syntax makes it very clear that each of the Exception-lists apply to a-expr. Fair enough. It's a bit hard to talk about multiple except expressions, though, as they're a problem unless formally supported - and they're almost never needed. Really, all you need to do is say never abut except-expressions without parentheses (which the current proposal and the parens around the exception bit only proposal both enforce), and then there's no problem. I expect that normal use of this won't include any form of chaining. Yes, it can - like any feature - be used abnormally, but at some point it's better to just drop it out as a statement. Key advantage to others may be that because the : is within the () [and the leading ( is quite nearby, making it obvious], it is less likely to be considered a statement boundary, and more easily explained as a special type of list syntax... not _really_ a list, because it is really code to be executed somewhat sequentially rather than data, and lists don't have : ... and not _really_ a dict constant, which does have :, because the Exception is not _really_ a key, but the syntax can draw on analogies with the dict constant syntax which will help people remember it, and even sort of understand that there is a pair-wise relationship between the Exception-list and the expression after the :, without repeating the except over and over. See the confusing terminology we have here? It might be called a list of except-expressions, but the brackets are round, and a list's are square. It's kinda like dict syntax, only again, the other sort of bracket, and it's wrong to try to construct a dict; it'd be too tempting to conflate this with some of the other current proposals for lazily-evaluated expressions (aka simpler syntax for lambda or other terms). This is, fundamentally, a multi-part expression on par with and and or: first, evaluate the primary expression; then, if an exception is raised, evaluate the exception list and see if it matches; then, if it matches, squash the exception and evaluate the default expression. You can't turn that into a dict, partly because you'd need to sort out lazy evaluation, and partly because a dict is unordered - if this is expanded to support multiple except clauses, they have to be processed in order. (You might, for instance, catch ZeroDivisionError, and then Exception, with different handling. It'd be VERY confusing for them to be processed in the wrong order, particularly if it happens unpredictably.) That's why I kept saying not _really_ :) It isn't a list, but it has an order requirement; it isn't a dict, but it has pairs; and finally, it isn't data, but code. But nonetheless the analogies are somewhat useful. Are there any other expressions that allow parens around a part of the expression, without the stuff inside them becoming a completely separate sub-expression? Sure. Function invocation. You can claim (and it is accurate) that the stuff inside is somewhat independent of the actual function called, but the syntax is function-name open-paren parameter-list close-paren, and the stuff in the parens would be a tuple if it were purely data, except not quite a tuple because some items are pairs (name and value), but it winds up being neither a tuple, nor a list, nor a dict, but instead a complex structure related to code execution :) Actually, this sounds quite similar to value = expr except ( Exception1: default1, Exception2: default2, Exception3: default3, ) except that to get the pairing aspect of some parameters for a function call, you use = instead of :, and instead of a named function it has an expression and a keyword. Not being an expert parser generator, I don't know if the () could be made optional if there is only one exception-list, but that would also remove one of the benefits some folks might perceive with using this syntax, and would also make the analogy with function call syntax a little less comparable. Glenn ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Fri, Feb 28, 2014 at 1:30 AM, Glenn Linderman v+pyt...@g.nevcal.comwrote: value = expr except ( Exception1: default1, Exception2: default2, Exception3: default3, ) except that to get the pairing aspect of some parameters for a function call, you use = instead of :, and instead of a named function it has an expression and a keyword. [ Cue people suggesting the use of '=' or '=' or '-' instead of ':' ] Not being an expert parser generator, I don't know if the () could be made optional if there is only one exception-list, but that would also remove one of the benefits some folks might perceive with using this syntax, and would also make the analogy with function call syntax a little less comparable. I believe it's possible, but it's probably tricky: the parser has to consider two or three cases: 1. expr1 except expr2: expr4 2. expr1 except (expr2: expr4) 3. expr1 except (expr2, expr3): expr4 4. expr1 except ((expr2, expr3): expr4) (for simplicity I use 'expr' here, which is entirely the wrong thing to do in terms of CPython's grammar: there's different types of expressions for different situations. #2 and #4 are actually automatically derived from #1 and #3 by 'expr' including tuples and parenthesized expressions.) CPython's parser is a LL(1) parser, which means it can look ahead 1 character to choose between alternatives (and that's not going to change, Guido likes it this way -- and so I do, personally :). Looking at #2 and #3 you can't tell which alternative to use until you see the ':' or ',' after 'expr2', which is too late. The only way to handle that, I think, is to include all possible alternatives in the grammar for the 'except' statement, duplicating logic and definitions from a lot of places. We already do this kind of thing to deal with other potentially-ambiguous situations (to handle dicts and sets and dict comprehensions and set comprehensions, for example) but this would be even more duplication. It would be easier if we weren't talking about '(' or any other token that can be part of a normal expression ;-P [ Cue people suggesting the use of 'expr1 except expr2: expr4 '... ] -- Thomas Wouters tho...@python.org Hi! I'm an email virus! Think twice before sending your email to help me spread! ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Fri, Feb 28, 2014 at 8:30 PM, Glenn Linderman v+pyt...@g.nevcal.com wrote: Are there any other expressions that allow parens around a part of the expression, without the stuff inside them becoming a completely separate sub-expression? Sure. Function invocation. You can claim (and it is accurate) that the stuff inside is somewhat independent of the actual function called, but the syntax is function-name open-paren parameter-list close-paren, and the stuff in the parens would be a tuple if it were purely data, except not quite a tuple because some items are pairs (name and value), but it winds up being neither a tuple, nor a list, nor a dict, but instead a complex structure related to code execution :) Thanks, that's exactly the sort of example I was looking for :) For some reason I mentally blanked and didn't think of that. My point is, if you're going to look for parens around the bit after except, we should look at styling and layout that follows how that's done. As TW says: [ Cue people suggesting the use of '=' or '=' or '-' instead of ':' ] If this is to be laid out like a function call, '=' would indeed make sense. But let's stick to the colon for now, so this is a mix of dict-style and function-call-style. expr except(Exception: default) In a more function-call-style layout, that would be: expr except(Exception=default) Both of those look reasonable, and they're tying the parens to the word except so it can't *actually* be a function call. Then it looks like it should be laid out like this: except(expr, Exception=default) and it really *is* looking like a function call - and now it's hit the uncanny valley [1], where it's close enough to be a problem (eg because of lazy evaluation, or because Exception could be (AttributeError, KeyError), which can't be a keyword argument). I don't like this last form; does anyone else support it? Removing the space after the word except makes me a lot less averse to this form. Funny how stylistic choices can influence a structural one! Here are a few more examples. How do other people feel about them? cond = args[1] except(IndexError: None) pwd = os.getcwd() except(OSError: None) e.widget = self._nametowidget(W) except(KeyError=W) line = readline() except(StopIteration='') _CONFIG_VARS['abiflags'] = sys.abiflags except(AttributeError: '') def getNamedItem(self, name): return self._attrs[name] except(KeyError: None) g = grp.getgrnam(tarinfo.gname)[2] except(KeyError=tarinfo.gid) u = pwd.getpwnam(tarinfo.uname)[2] except(KeyError=tarinfo.uid) mode = f.mode except(AttributeError: 'rb') return sys._getframe(1) except(AttributeError=None) ips.append(ip.ip except(AttributeError: ip.network_address)) dirlist.append(_os.getcwd() except((AttributeError, OSError)=_os.curdir)) The last one is really critical here, I think. It's the only stdlib example I could find that catches two different errors (IIRC). Here it is with the colon: dirlist.append(_os.getcwd() except((AttributeError, OSError): _os.curdir)) Thoughts? ChrisA [1] http://tvtropes.org/pmwiki/pmwiki.php/Main/UncannyValley ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 28 February 2014 21:46, Chris Angelico ros...@gmail.com wrote: On Fri, Feb 28, 2014 at 8:30 PM, Glenn Linderman v+pyt...@g.nevcal.com wrote: Are there any other expressions that allow parens around a part of the expression, without the stuff inside them becoming a completely separate sub-expression? Sure. Function invocation. You can claim (and it is accurate) that the stuff inside is somewhat independent of the actual function called, but the syntax is function-name open-paren parameter-list close-paren, and the stuff in the parens would be a tuple if it were purely data, except not quite a tuple because some items are pairs (name and value), but it winds up being neither a tuple, nor a list, nor a dict, but instead a complex structure related to code execution :) Thanks, that's exactly the sort of example I was looking for :) For some reason I mentally blanked and didn't think of that. My point is, if you're going to look for parens around the bit after except, we should look at styling and layout that follows how that's done. Also generator expressions and most uses of yield or yield from as embedded expressions. Parentheses are our general this next bit may not be following the normal syntax rules utility, in addition to being used to override the normal precedence rules (square brackets and curly braces similarly denote regions where the parsing rules may differ from the top level ones). As far as the specific problem I'm attacking with this variant of the proposal goes, one of the recurring reactions from different people has been but colons are used to introduce suites, not expressions. This impression is not, in fact, correct, as the colon is already used as a subexpression separator in four cases: * dict display key:value pairs * slice notation start:stop:step triples * function parameter : annotation separation * lambda expression arg list : return value separation PEP 463 just adds a fifth such case, as an exception spec:result separator. The preferred notation in the PEP most resembles the existing lambda use case, with except instead of lambda, an exception handling spec instead of an argument list and an additional leading expression: (expr except Exception: default) Lots of people don't like the lambda notation though, so it isn't necessarily a particularly compelling parallel to use. By contrast, it's rare to hear any objections to the {key:value} dict display syntax. Hence the proposed tweak to the syntax to define an exception handler expression syntax that is analogous to a dict display rather than a lambda expression: expr except (Exception: default) However, I have realised that there *is* a major downside to that notation, which is that it lacks the connotations of lazy evaluation associated with lambda expressions, whereas the default result of an except expression won't be evaluated at all if the exception isn't thrown. So I think that on balance, I actually do prefer your current proposal. That said, I do think this is a variant worth discussing explicitly in the PEP, if only to remind people that there's definitely precedent for using a colon to separate two subexpressions inside a larger expression element - it's not *just* used to introduce suites, even though that is by far the most *common* use case. Cheers, Nick. -- Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Fri, Feb 28, 2014 at 11:51 PM, Nick Coghlan ncogh...@gmail.com wrote: So I think that on balance, I actually do prefer your current proposal. That said, I do think this is a variant worth discussing explicitly in the PEP, if only to remind people that there's definitely precedent for using a colon to separate two subexpressions inside a larger expression element - it's not *just* used to introduce suites, even though that is by far the most *common* use case. I've added a bit more to the PEP about that. https://github.com/Rosuav/ExceptExpr/commit/f32387 Does that explain it, do you think? ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 28 February 2014 23:07, Chris Angelico ros...@gmail.com wrote: On Fri, Feb 28, 2014 at 11:51 PM, Nick Coghlan ncogh...@gmail.com wrote: So I think that on balance, I actually do prefer your current proposal. That said, I do think this is a variant worth discussing explicitly in the PEP, if only to remind people that there's definitely precedent for using a colon to separate two subexpressions inside a larger expression element - it's not *just* used to introduce suites, even though that is by far the most *common* use case. I've added a bit more to the PEP about that. https://github.com/Rosuav/ExceptExpr/commit/f32387 Does that explain it, do you think? Yeah, that works. You may also want to add a common objections section to explicitly cover the but colons introduce suites objection. That would provide a space to explicitly list all of the current not introducing a suite use cases for the colon in Python's syntax, since increasing that tally from four to five is less radical than introducing the first non-suite related use case for the symbol. Cheers, Nick. -- Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Fri, Feb 28, 2014 at 11:51 PM, Nick Coghlan ncogh...@gmail.com wrote: Are there any other expressions that allow parens around a part of the expression, without the stuff inside them becoming a completely separate sub-expression? Also generator expressions and most uses of yield or yield from as embedded expressions. Parentheses are our general this next bit may not be following the normal syntax rules utility, in addition to being used to override the normal precedence rules (square brackets and curly braces similarly denote regions where the parsing rules may differ from the top level ones). In those cases, the stuff inside the parens is the entire syntactic structure of that sub-element, right? I was looking for something where there's syntax inside and syntax outside the parens, where what's in the parens isn't just an expression or tuple, so I could try laying out an except expression to imitate that style. The function call is excellent; removing one space from the layout did make the expression look better, but as explained above, I still prefer the current form. Would like to make the parens optional; maybe make them mandatory if there are two except-expressions abutting, or something, but I'd like to simplify the syntax for the common case. Otherwise, current syntax is still my personal preferred. Of course, we still have to convince Guido that this is a good idea at all, syntax or no :) ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sat, Mar 1, 2014 at 12:24 AM, Nick Coghlan ncogh...@gmail.com wrote: Yeah, that works. You may also want to add a common objections section to explicitly cover the but colons introduce suites objection. That would provide a space to explicitly list all of the current not introducing a suite use cases for the colon in Python's syntax, since increasing that tally from four to five is less radical than introducing the first non-suite related use case for the symbol. https://github.com/Rosuav/ExceptExpr/commit/b770f9 Any other objections that should be listed? ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 2/28/2014 4:51 AM, Nick Coghlan wrote: The preferred notation in the PEP most resembles the existing lambda use case, with except instead of lambda, an exception handling spec instead of an argument list and an additional leading expression: (expr except Exception: default) Lots of people don't like the lambda notation though, so it isn't necessarily a particularly compelling parallel to use. Thank you for explaining why I find the above notation awkward. : as introducing a suite never bothered me, because, as you've now enumerated, there are other uses of :. But the lambda syntax parallel is what I don't like about it... I find the lambda syntax hard to read. By contrast, it's rare to hear any objections to the {key:value} dict display syntax. Hence the proposed tweak to the syntax to define an exception handler expression syntax that is analogous to a dict display rather than a lambda expression: expr except (Exception: default) However, I have realised that there*is* a major downside to that notation, which is that it lacks the connotations of lazy evaluation associated with lambda expressions, whereas the default result of an except expression won't be evaluated at all if the exception isn't thrown. You are overlooking that the keyword except provides exactly the connotation of lazy evaluation, so if this is your only reason for preferring the lambda syntax, you just erased it :) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sat, Mar 1, 2014 at 12:24 PM, Glenn Linderman v+pyt...@g.nevcal.com wrote: You are overlooking that the keyword except provides exactly the connotation of lazy evaluation, so if this is your only reason for preferring the lambda syntax, you just erased it :) Statements are always executed sequentially. That's not lazy evaluation, that's just the way statements are :) ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 21 Feb 2014, at 16:52, Chris Angelico ros...@gmail.com wrote: On Sat, Feb 22, 2014 at 1:34 AM, Brett Cannon br...@python.org wrote: While I like the general concept, I agree that it looks too much like a crunched statement; the use of the colon is a non-starter for me. I'm sure I'm not the only one whose brain has been trained to view a colon in Python to mean statement, period. This goes against that syntactic practice and just doesn't work for me. I'm -1 with the current syntax, but it can go into the + range if a better syntax can be chosen. We bikeshedded that extensively on -ideas. The four best options are: value = (expr except Exception: default) value = (expr except Exception - default) value = (expr except Exception pass default) value = (expr except Exception then default) Note that the last option involves the creation of a new keyword. Would any of the others feel better to you? What about (also mentioned in the PEP)? value = (expr except Exception try default) This seems to read nicely, although “try” is at a completely different position than it is in the equivalent try statement. I like the general idea, but like Brett I don’t like using a colon here at all. Ronald P.S. Sorry if this way already brought up, I’ve browsed through most of the threads on this on -ideas and -dev, but haven’t read all messages. ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/ronaldoussoren%40mac.com ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Thu, Feb 27, 2014 at 7:44 PM, Ronald Oussoren ronaldousso...@mac.com wrote: What about (also mentioned in the PEP)? value = (expr except Exception try default) This seems to read nicely, although “try” is at a completely different position than it is in the equivalent try statement. I like the general idea, but like Brett I don’t like using a colon here at all. I see your although clause to be quite a strong objection. In the statement form of an if, you have: if cond: true_suite else: false_suite In the expression form, you have: true_expr if cond else false_expr Personally, I think it's a weakness of the if-expression that they're not in the same order (cond, true_expr, false_expr), but they're still introduced with the same keywords. The 'if' keyword is followed by the condition, and the 'else' keyword by the false stuff. Putting try followed by the default is confusing, because any exception raised in the default-expr will bubble up. Stealing any other keyword from the try/except block would make just as little sense: expr except Exception finally default # finally implies something that always happens expr except Exception else default # else implies *no* exception expr except Exception try default # try indicates the initial expr, not the default default except Exception try expr # breaks L-R evaluation order Left to right evaluation order is extremely important to me. I don't know about anyone else, but since I'm the one championing the PEP, you're going to have to show me a *really* strong incentive to reword it to advocate something like the last one :) This is stated in the PEP: http://www.python.org/dev/peps/pep-0463/#alternative-proposals Using try and except leaves the notation mentally ambiguous as to which of the two outer expressions is which. It doesn't make perfect sense either way, and I expect a lot of people would be flicking back to the docs constantly to make sure they had it right. It's hard when there's confusion across languages (try writing some code in REXX and Python that uses division and modulo operators - 1234/10 - 123.4 in Py3 and REXX, but 1234//10 and 1234%10 have opposite meaning); it's unnecessarily hard to have the same confusion in different places in the same language. ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 27 Feb 2014, at 11:09, Chris Angelico ros...@gmail.com wrote: On Thu, Feb 27, 2014 at 7:44 PM, Ronald Oussoren ronaldousso...@mac.com wrote: What about (also mentioned in the PEP)? value = (expr except Exception try default) This seems to read nicely, although “try” is at a completely different position than it is in the equivalent try statement. I like the general idea, but like Brett I don’t like using a colon here at all. I see your although clause to be quite a strong objection. In the statement form of an if, you have: I’m not convinced that this is a strong objection. The order of keywords is different, but that doesn’t have to be problem. if cond: true_suite else: false_suite In the expression form, you have: true_expr if cond else false_expr […] Putting try followed by the default is confusing, because any exception raised in the default-expr will bubble up. Stealing any other keyword from the try/except block would make just as little sense: expr except Exception finally default # finally implies something that always happens expr except Exception else default # else implies *no* exception expr except Exception try default # try indicates the initial expr, not the default I didn’t parse the expression this way at all, but quite naturally parsed is as “use expr, and try using default if expr raises Exception” and not as a RTL expression. default except Exception try expr # breaks L-R evaluation order Left to right evaluation order is extremely important to me. I agree with that, RTL evaluation would be pretty odd in Python. I don't know about anyone else, but since I'm the one championing the PEP, you're going to have to show me a *really* strong incentive to reword it to advocate something like the last one :) This is stated in the PEP: http://www.python.org/dev/peps/pep-0463/#alternative-proposals Using try and except leaves the notation mentally ambiguous as to which of the two outer expressions is which. It doesn't make perfect sense either way, and I expect a lot of people would be flicking back to the docs constantly to make sure they had it right. Really? The evaluation order you mention in above didn’t make sense to me until I tried to make sense of it. Ronald ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Thu, Feb 27, 2014 at 9:44 PM, Ronald Oussoren ronaldousso...@mac.com wrote: expr except Exception try default # try indicates the initial expr, not the default I didn’t parse the expression this way at all, but quite naturally parsed is as “use expr, and try using default if expr raises Exception” and not as a RTL expression. Thing is, in the statement form, try doing this means do this, and you might get an exception, so deal with it. In the 'try default' form, try this means oops, you got an exception, so try this instead. It's using try in the opposite way. default except Exception try expr # breaks L-R evaluation order Left to right evaluation order is extremely important to me. I agree with that, RTL evaluation would be pretty odd in Python. Really? The evaluation order you mention in above didn’t make sense to me until I tried to make sense of it. The default except Exception try expr notation has try followed by the thing that might raise an exception, which mimics the statement. The expr except Exception try default notation evaluates from left to right. Both make some sense, and I'd say it's on balance which is the more likely to be expected. Imagine an overall expression where it's ambiguous: value = (d[foo] except KeyError try d[spam]) Which one do you expect to be tried first? I'd say you could poll a bunch of moderately-experienced Python programmers and get both answers in reasonable numbers. ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 27 February 2014 20:44, Ronald Oussoren ronaldousso...@mac.com wrote: On 27 Feb 2014, at 11:09, Chris Angelico ros...@gmail.com wrote: On Thu, Feb 27, 2014 at 7:44 PM, Ronald Oussoren ronaldousso...@mac.com wrote: What about (also mentioned in the PEP)? value = (expr except Exception try default) This seems to read nicely, although try is at a completely different position than it is in the equivalent try statement. I like the general idea, but like Brett I don't like using a colon here at all. I see your although clause to be quite a strong objection. In the statement form of an if, you have: I'm not convinced that this is a strong objection. The order of keywords is different, but that doesn't have to be problem. As Chris notes, the problem is that if you use try, the two plausible interpretations are: 1. Evaluates left-to-right, try introduces a different part of the syntax (different from every past statement-expression conversion where the clauses are reordered, but almost always introduced by the same keywords as they are in the statement form) 2. Evaluates right-to-left, try introduces the expressions covered by the exception handler (this is just backwards, and significantly harder to follow than even the middle first conditional expression) Neither interpretation is particularly acceptable, and the fact that the other interpretation would remain plausible regardless is a further strike against both of them. Personally, I think the PEP makes a good case for particular semantics with a spelling that isn't great, but isn't completely abhorrent either. I definitely think it represents an improvement over the status quo, which is an ongoing proliferation of function-based special cases for doing particular kinds of exception handling as an expression, and the spelling advocated for in the PEP seems like the best of the (many) alternatives that have been proposed. The way I get the colon in the proposed syntax to make sense to my brain is to view it as being more like the colon in a dictionary key:value pair than it is like the one that introduces a suite or the body of a lambda expression: (lst[2] except {IndexError: No value}) The analogy isn't exact (since exception handling is isinstance() based rather than equality based), but I think it gives the right general flavour in terms of the intended meaning of the colon in this construct. The analogy could likely be encouraged and strengthened by changing the parentheses requirements to make this read more like a binary except expression with a parenthesised RHS rather than a ternary expression: lst[2] except (IndexError: No value) Catching multiple errors would involve a parenthesised tuple as the key: f() except ((TypeError, AttributeError): No value) The deferred multiple except clauses part of the PEP could also change to be more dict display like: value = expr except ( Exception1: default1, Exception2: default2, Exception3: default3, ) Writing out those examples, I actually like that version (where the parentheses are still mandatory, but the left paren is after the except keyword rather than before the first expression) better than the one currently in the PEP. It also avoids the weirdly unbalanced look of the variant that had the left paren *before* the except keyword. The main downside I see is that the exception handling definition syntax would only be permitted in that specific location, but still look a lot like an ordinary parenthesised expression. Cheers, Nick. -- Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 2/27/2014 4:57 AM, Nick Coghlan wrote: The way I get the colon in the proposed syntax to make sense to my brain is to view it as being more like the colon in a dictionary key:value pair than it is like the one that introduces a suite or the body of a lambda expression: (lst[2] except {IndexError: No value}) The analogy isn't exact (since exception handling is isinstance() based rather than equality based), but I think it gives the right general flavour in terms of the intended meaning of the colon in this construct. The analogy could likely be encouraged and strengthened by changing the parentheses requirements to make this read more like a binary except expression with a parenthesised RHS rather than a ternary expression: lst[2] except (IndexError: No value) Catching multiple errors would involve a parenthesised tuple as the key: f() except ((TypeError, AttributeError): No value) The deferred multiple except clauses part of the PEP could also change to be more dict display like: value = expr except ( Exception1: default1, Exception2: default2, Exception3: default3, ) Writing out those examples, I actually like that version (where the parentheses are still mandatory, but the left paren is after the except keyword rather than before the first expression) better than the one currently in the PEP. It also avoids the weirdly unbalanced look of the variant that had the left paren*before* the except keyword. The main downside I see is that the exception handling definition syntax would only be permitted in that specific location, but still look a lot like an ordinary parenthesised expression. Cheers, Nick. +1 f() except ((TypeError, AttributeError): No value) is a nice extension to the idea of value = expr except ( Exception1: default1, Exception2: default2, Exception3: default3, ) Which I've liked since I first saw it, as it neatly solves handling multiple except clauses. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Fri, Feb 28, 2014 at 6:36 AM, Glenn Linderman v+pyt...@g.nevcal.com wrote: +1 f() except ((TypeError, AttributeError): No value) is a nice extension to the idea of value = expr except ( Exception1: default1, Exception2: default2, Exception3: default3, ) Which I've liked since I first saw it, as it neatly solves handling multiple except clauses. You can already list multiple exception types. The definition of the exception_list is exactly as per the try/except statement (bar the 'as' keyword, which I would love to see implemented some day). ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
I've added another utility script to my PEP draft repo: https://github.com/Rosuav/ExceptExpr/blob/master/replace_except_expr.py It's built out of some pretty horrendous hacks, it makes some assumptions about code layout (eg spaces for indentation, and a try/except block never has anything else on the same line(s)), and the code's a bit messy, but it does work. I ran it on the Python stdlib and it produced a whole lot of edits (I had it keep the old version in comments, bracketed with markers with the text PEP 463 in them, which makes it easy to find and analyze); one file (with two try blocks) causes a test failure, but all the rest still pass. If people can try the script on their own codebases and see how it looks, that'd be great. I recommend first running the script with ast.Expr handling removed (as per the file you see above), and then maybe running it with that one line commented out. You'll get a lot of unhelpful change suggestions from the double-expression handler. Could a core committer please apply the last few changes to the PEP? https://raw.github.com/Rosuav/ExceptExpr/master/pep-0463.txt or the diff is below. I think this is the last important change left; things have gone fairly quiet here, and I think the PEP's about ready to request pronouncement, unless someone knows of something I've forgotten. (Have I said I'll write up a paragraph about that about anything and not done it yet? Now's the perfect time to remind me.) Thanks! ChrisA diff -r 5f63c8a92d1c pep-0463.txt --- a/pep-0463.txt Mon Feb 24 14:22:46 2014 -0800 +++ b/pep-0463.txt Fri Feb 28 08:25:33 2014 +1100 @@ -43,6 +43,34 @@ * statistics.mean(data) - no way to handle an empty iterator +Had this facility existed early in Python's history, there would have been +no need to create dict.get() and related methods; the one obvious way to +handle an absent key would be to respond to the exception. One method is +written which signal the absence in one way, and one consistent technique +is used to respond to the absence. Instead, we have dict.get(), and as of +Python 3.4, we also have min(... default=default), and myriad others. We +have a LBYL syntax for testing inside an expression, but there is currently +no EAFP notation; compare the following:: + +# LBYL: +if key in dic: +process(dic[key]) +else: +process(None) +# As an expression: +process(dic[key] if key in dic else None) + +# EAFP: +try: +process(dic[key]) +except KeyError: +process(None) +# As an expression: +process(dic[key] except KeyError: None) + +Python generally recommends the EAFP policy, but must then proliferate +utility functions like dic.get(key,None) to enable this. + Rationale = @@ -338,6 +366,19 @@ except KeyError: u = tarinfo.uid +Look up an attribute, falling back on a default:: +mode = (f.mode except AttributeError: 'rb') + +# Lib/aifc.py:882: +if hasattr(f, 'mode'): +mode = f.mode +else: +mode = 'rb' + +return (sys._getframe(1) except AttributeError: None) +# Lib/inspect.py:1350: +return sys._getframe(1) if hasattr(sys, _getframe) else None + Perform some lengthy calculations in EAFP mode, handling division by zero as a sort of sticky NaN:: @@ -616,7 +657,7 @@ it would be with the statement form, and as its syntax is a point on which consensus has not been reached, the entire feature is deferred. -Multiple 'except' keywords can be used, and they will all catch +Multiple 'except' keywords could be used, and they will all catch exceptions raised in the original expression (only):: # Will catch any of the listed exceptions thrown by expr; -- end -- ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Fri, Feb 28, 2014 at 8:29 AM, Chris Angelico ros...@gmail.com wrote: @@ -43,6 +43,34 @@ * statistics.mean(data) - no way to handle an empty iterator +Had this facility existed early in Python's history, there would have been +no need to create dict.get() and related methods; the one obvious way to +handle an absent key would be to respond to the exception. One method is +written which signal the absence in one way, and one consistent technique Doh! Typical... I notice the typo only after hitting send. This should be which signals. The linked-to draft file has been updated. ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 28 Feb 2014 05:56, Chris Angelico ros...@gmail.com wrote: On Fri, Feb 28, 2014 at 6:36 AM, Glenn Linderman v+pyt...@g.nevcal.com wrote: +1 f() except ((TypeError, AttributeError): No value) is a nice extension to the idea of value = expr except ( Exception1: default1, Exception2: default2, Exception3: default3, ) Which I've liked since I first saw it, as it neatly solves handling multiple except clauses. You can already list multiple exception types. The definition of the exception_list is exactly as per the try/except statement (bar the 'as' keyword, which I would love to see implemented some day). Note that this example is covering the deferred case of multiple except clauses that resolve to different values, not the already handled case of multiple exception types that resolve to the same value. Anyway, even if you choose not to switch the parenthesis requirement in PEP, it should at least make the colon as in dict display, not as in suite introduction comparison, and note this as an alternative proposal for the required parentheses. Cheers, Nick. ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/ncoghlan%40gmail.com ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Fri, Feb 28, 2014 at 1:12 PM, Glenn Linderman v+pyt...@g.nevcal.com wrote: Yes. But the point is really the location of the (), sorry if my nice extension comment is throwing you off that track. Ah! I see. We touched on this syntax on -ideas, but at the time, the proposed syntax didn't have parens around the outside. Either location will solve most of the same problems (like precedence/associativity versus multiple except clauses), but shrinking down to just the exception list and default value makes it look very different. It looks like what's inside should be an expression, which it isn't. What's the advantage of this form? What's its key advantage over the parens-around-the-whole-thing form? ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 2/27/2014 7:46 PM, Chris Angelico wrote: On Fri, Feb 28, 2014 at 1:12 PM, Glenn Linderman v+pyt...@g.nevcal.com wrote: Yes. But the point is really the location of the (), sorry if my nice extension comment is throwing you off that track. Ah! I see. We touched on this syntax on -ideas, but at the time, the proposed syntax didn't have parens around the outside. Either location will solve most of the same problems (like precedence/associativity versus multiple except clauses), but shrinking down to just the exception list and default value makes it look very different. It looks like what's inside should be an expression, which it isn't. What's the advantage of this form? What's its key advantage over the parens-around-the-whole-thing form? Key advantage to me is that if a function call or other expression may produce multiple exceptions, the syntax doesn't require repeating the except over and over. By not repeating the except over and over, there is less ambiguity about what expression the Exception-lists apply to, when there is more than one Exception list in the expression. Whereas the current PEP syntax has ambiguity regarding how to interpret a-expr except except-list-b: b-expr except except-list-c: c-expr (does the 2nd except apply to a-expr or b-expr?), without parentheses, and, as far as I am concerned, even with the parentheses, this syntax makes it very clear that each of the Exception-lists apply to a-expr. Key advantage to others may be that because the : is within the () [and the leading ( is quite nearby, making it obvious], it is less likely to be considered a statement boundary, and more easily explained as a special type of list syntax... not _really_ a list, because it is really code to be executed somewhat sequentially rather than data, and lists don't have : ... and not _really_ a dict constant, which does have :, because the Exception is not _really_ a key, but the syntax can draw on analogies with the dict constant syntax which will help people remember it, and even sort of understand that there is a pair-wise relationship between the Exception-list and the expression after the :, without repeating the except over and over. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 22/02/2014 21:26, Tim Delaney wrote: On 23 February 2014 02:29, Nick Coghlan ncogh...@gmail.com mailto:ncogh...@gmail.com wrote: On 22 Feb 2014 22:15, Stephen J. Turnbull step...@xemacs.org mailto:step...@xemacs.org wrote: Antoine Pitrou writes: Chris Angelico ros...@gmail.com mailto:ros...@gmail.com wrote: hasattr(x,y) - (x.y or True except AttributeError: False) But it's not the same. hasattr() returns a boolean, not an arbitrary value. I think he meant hasattr(x,y) - (x.y and True except AttributeError: False) With PEP 463, the explicit equivalent of hasattr() would be something like : hasattr(x,y) - (bool(x.y) or True except AttributeError: False) That would work, but I think I'd prefer: hasattr(x,y) - bool(x.y or True except AttributeError: False) Makes it clearer IMO that the entire expression will always return a boolean. This also works: hasattr(x,y) - (lambda v: True)(x.y) except AttributeError: False Which is less obscure is a matter of judgement. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
Some of your points have been answered by others, I'll try to avoid repetition. On 21/02/2014 19:04, Yury Selivanov wrote: [snip] Inconvenience of dict[] raising KeyError was solved by introducing the dict.get() method. And I think that dct.get('a', 'b') is 1000 times better than dct['a'] except KeyError: 'b' Do you? I don't. Explicit is better than implicit. I think this may be partly a matter of familiarity. Translate numbers to names, falling back on the numbers:: g = grp.getgrnam(tarinfo.gname)[2] except KeyError: tarinfo.gid u = pwd.getpwnam(tarinfo.uname)[2] except KeyError: tarinfo.uid # Lib/tarfile.py:2198: try: g = grp.getgrnam(tarinfo.gname)[2] except KeyError: g = tarinfo.gid try: u = pwd.getpwnam(tarinfo.uname)[2] except KeyError: u = tarinfo.uid This one is a valid example, but totally unparseable by humans. Again, I find the more concise version easier to read than the original. It is dense, yes. It takes time to read and absorb, sure - but so does the original 8-line version. And it makes the repetition of the same code structure much more obvious. I think all of the above more readable with try statement. Retrieving a message from either a cache or the internet, with auth check:: logging.info(Message shown to user: %s,((cache[k] except LookupError: (backend.read(k) except OSError: 'Resource not available') ) if check_permission(k) else 'Access denied' ) except BaseException: This is like a bare except clause) try: if check_permission(k): try: _ = cache[k] except LookupError: try: _ = backend.read(k) except OSError: _ = 'Resource not available' else: _ = 'Access denied' except BaseException: _ = This is like a bare except clause logging.info(Message shown to user: %s, _) I think there is a consensus that this was a poor example, unless intended to show how the new construction (like any other) could be abused to produce hard-to-understand code. If you replace '_' with a 'msg' (why did you use '_'??) then try statements are *much* more readable. [snip] Lib/ipaddress.py:343:: try: ips.append(ip.ip) except AttributeError: ips.append(ip.network_address) Becomes:: ips.append(ip.ip except AttributeError: ip.network_address) or it may become: ips.append(getattr(ip, 'ip', ip.network_address)) or address = getattr(ip, 'ip', ip.network_address) ips.append(address) Please note that any of these is an improvement on the original, in that they don't trap an AttributeError evaluating ips.append. (The old try ... except syntax can be used incorrectly, just as any new syntax can.) --- All in all, your proposal scares me. I doesn't make python code readable, Again, a personal judgement. it doesn't solve the problem of overbroad exceptions handling (you have couple examples of overbroad handling in your PEP examples section). Yes, some examples look neat. But your syntax is much easier to abuse, than 'if..else' expression, Why? Any syntax can be abused. I can easily abuse if..else if I want to: ErrorMessage = (None if eggs else No eggs) if ham else No ham if eggs else No ham or eggs # Tested Suppose you were learning Python. Which is easier, to learn lots of special methods (dict.get, getattr etc.), or to learn ONE self-explanatory form of syntax that covers them all: Dict[Key] except KeyError: default List[Index] except IndexError: default x.y except AttributeError: default (Of course, I'm not saying Don't use getattr. Just that you could get by if you've never heard of it.) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 21/02/2014 23:36, Ethan Furman wrote: On 02/21/2014 02:26 PM, Eric V. Smith wrote: On 2/21/2014 5:06 PM, Greg Ewing wrote: On 21 February 2014 13:15, Chris Angelico wrote: Generator expressions require parentheses, unless they would be strictly redundant. Ambiguities with except expressions could be resolved in the same way, forcing nested except-in-except trees to be correctly parenthesized There would be no ambiguity if only nested excepts are allowed. If one wants to catch multiple exceptions from one expression, /and do something different for each one/, use the statement form as it's going to be clearer. For example: try: value = 1/x except ZeroDivisionError: try: value = 1/default['denominator'] except KeyError: value = NaN is much cleaner as: value = 1/x except ZeroDivisionError: 1/default['denominator'] except KeyError: NaN However, this: try: result = Parse(some_stuff) except MissingOperator: result = ... except InvalidOperand: result = ... except SomethingElse: result = ... would not benefit from being condensed into a single expression -- ~Ethan~ Funny, my feeling was exactly the reverse. :-) Probably because the latter seems to me to be a more natural thing to want to do (I find it easier to imagine use cases for it). And also because there is no way of getting exactly the same effect with a parenthesized except-expression: (expr except ValueError: ValueErrrorMessage) except NameError:NameErrorMessage # doesn't quite do what I want (here if expr raises a ValueError, evaluating ValueErrrorMessage which is mis-spelt will raise a NameError which will be misleadingly caught). But I guess the truth is that any except-expression which gets too long and complicated should be written some other way. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 22/02/2014 02:08, Glenn Linderman wrote: On 2/21/2014 5:06 PM, Jan Kaliszewski wrote: Or even (still being my favorite): msg = seq[i] except (IndexError: nothing) This syntax actually has a benefit: the parenthesized syntax after except could become a list, to allow handling different exceptions from the tried expression with different results: msg = seq[dictionary[i]] except (IndexError: nothing, KeyError: serious problems) It shouldn't be a true list. We need lazy evaluation of the default values. And if an unlisted exception is raised, we don't want any of the defaults evaluated. Rob Cliffe And still allows nesting: msg = seq[i] except (IndexError: dictionary[i] except (KeyError: no fallback data for %s % i)) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/rob.cliffe%40btinternet.com No virus found in this message. Checked by AVG - www.avg.com http://www.avg.com Version: 2012.0.2247 / Virus Database: 3705/6616 - Release Date: 02/22/14 ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
Yury Selivanov wrote: I think the Motivation section is pretty weak. I have normally wished for this when I was (semi- interactively) exploring a weakly structured dataset. Often, I start with a string, split it into something hopefully like records, and then start applying filters and transforms. I would prefer to write a comprehension instead of a for loop. Alas, without pre-editing, I can be fairly confident that the data is dirty. Sometimes I can solve it with a filter (assuming that I remember and don't mind the out-of-order evaluation): # The if value happens first, # so the 1/value turns out to be safe. [1/value for value in working_list if value] Note that this means dropping the bad data, so that items in this list will have different indices than those in the parent working_list. I would rather have written: [1/value except (TypeError, ZeroDivisionError): None] which would keep the matching indices, and clearly indicate where I now had missing/invalid data. Sometimes I solve it with a clumsy workaround: sum((e.weight if hasattr(e, 'weight') else 1.0) for e in working_list) But the hasattr implies that I am doing some sort of classification based on whether or not the element has a weight. The true intent was to recognize that while every element does have a weight, the representation that I'm starting from didn't always bother to store it -- so I am repairing that before processing. sum(e.weight except AttributeError: 1) Often I give up, and create a junky helper function, or several. But to avoid polluting the namespace, I may leave it outside the class, or give it a truly bad name: def __only_n2(worklist): results = [] for line in worklist: line=line.strip() if not line: # or maybe just edit the input file... continue split1=line.split(, ) if 7 != len(split1): continue if n2 == split1[3]: results.append(split1) return results worklist_n2 = __only_n2(worklist7) In real life code, even after hand-editing the input data to fix a few cases, I recently ended up with: class VoteMark: ... @classmethod def from_property(cls, voteline): # print (voteline) count, _junk, prefs = voteline.partition(: ) return cls(count, prefs) ... # module level scope def make_votes(vs=votestring): return [VoteMark.from_property(e) for e in vs.splitlines()] vs=make_votes() You can correctly point out that I was being sloppy, and that I *should* have gone back to clean it up. But I wouldn't have had to clean up either the code or the data (well, not as much), if I had been able to just keep the step-at-a-time transformations I was building up during development: vs=[(VoteMark(*e.strip().split(: )) except (TypeError, ValueError): None) for e in votestring.splitlines()] Yes, the first line is still doing too much, and might be worth a helper function during cleanup. But it is already better than an alternate constructor that exists only to simplify a single (outside the class) function that is only called once. Which in turn is better than the first draft that was so ugly that I actually did fix it during that same work session. Inconvenience of dict[] raising KeyError was solved by introducing the dict.get() method. And I think that dct.get('a', 'b') is 1000 times better than dct['a'] except KeyError: 'b' I don't. dct.get('a', default='b') would be considerably better, but it would still imply that missing values are normal. So even after argclinic is fully integrated, there will still be times when I prefer to make it explicit that I consider this an abnormal case. (And, as others have pointed out, .get isn't a good solution when the default is expensive to compute.) Consider this example of a two-level cache:: for key in sequence: x = (lvl1[key] except KeyError: (lvl2[key] except KeyError: f(key))) I'm sorry, it took me a minute to understand what your example is doing. I would rather see two try..except blocks than this. Agreed -- like my semi-interactive code above, it does too much on one line. I don't object as much to: for key in sequence: x = (lvl1[key] except KeyError: (lvl2[key] except KeyError: f(key))) Retrieve an argument, defaulting to None:: cond = args[1] except IndexError: None # Lib/pdb.py:803: try: cond = args[1] except IndexError: cond = None cond = None if (len(args) 2) else args[1] This is an area where tastes will differ. I view the first as saying that not having a cond would be unusual, or at least a different kind of call. I view your version as a warning that argument parsing will be complex, and that
Re: [Python-Dev] PEP 463: Exception-catching expressions
Greg Ewing suggested: This version might be more readable: value = lst[2] except No value if IndexError Ethan Furman asked: It does read nicely, and is fine for the single, non-nested, case (which is probably the vast majority), but how would it handle nested exceptions? With parentheses. Sometimes, the parentheses will make a complex expression ugly. Sometimes, a complex expression should really be factored into pieces anyway. Hopefully, these times are highly correlated. The above syntax does lend itself somewhat naturally to multiple *short* except clauses: value = (lst[2] except No value if IndexError except Bad Input if TypeError) and nested exception expressions are at least possible, but deservedly ugly: value = (lvl1[name] except (lvl2[name] except (compute_new_answer(name) except None if AppValueError) if KeyError) if KeyError) This also makes me wonder whether the cost of a subscope (for exception capture) could be limited to when an exception actually occurs, and whether that might lower the cost enough to make the it a good tradeoff. def myfunc1(a, b, e): assert main scope e value == e e = main scope e value value = (myfunc1(val1, val2, e) except e.reason if AppError as e) assert main scope e value == e -jJ -- If there are still threading problems with my replies, please email me with details, so that I can try to resolve them. -jJ ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Tue, Feb 25, 2014 at 11:27 AM, Jim J. Jewett jimjjew...@gmail.com wrote: This also makes me wonder whether the cost of a subscope (for exception capture) could be limited to when an exception actually occurs, and whether that might lower the cost enough to make the it a good tradeoff. def myfunc1(a, b, e): assert main scope e value == e e = main scope e value value = (myfunc1(val1, val2, e) except e.reason if AppError as e) assert main scope e value == e I'm sure it could. But there aren't many use-cases. Look at the one example I was able to find in the stdlib: http://legacy.python.org/dev/peps/pep-0463/#capturing-the-exception-object It's hardly a shining example of the value of the proposal. Got any really awesome demo that requires 'as'? Most of the supporting examples use something like KeyError where it's simply was an exception thrown or not. ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sun, 23 Feb 2014, Nick Coghlan wrote: Note that mandatory parentheses means we can duck the precedence question entirely, which I count as another point in favour of requiring them :) Careful, if you take that too far then Python 4 will have to be Scheme. ;-) Isaac Morland CSCF Web Guru DC 2619, x36650 WWW Software Specialist ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
Chris Angelico, 21.02.2014 04:15: Just as PEP 308 introduced a means of value-based conditions in an expression, this system allows exception-based conditions to be used as part of an expression. [...] This currently works:: lst = [1, 2, None, 3] value = lst[2] or No value The proposal adds this:: lst = [1, 2] value = lst[2] except IndexError: No value I see a risk of interfering with in-place assignment operators, e.g. x /= y except ZeroDivisionError: 1 might not do what one could expect, because (as I assume) it would behave differently from x = x / y except ZeroDivisionError: 1 I think that falls under the overly broad exception handling issue. If you want to include the assignment, you'll have to spell out the try-except block yourself. I find the difference in the two behaviours very unfortunate, though. This also reduces the scope of applicability somewhat. Cython has typed assignments, so a straight forward idea would be to handle TypeErrors in assignments like this: cdef str s s = x except TypeError: str(x) However, I guess that would similarly counter the idea of exception handling in an *expression*, and the correct and non-ambiguous way to do this would be to spell out the try-except block. Summing it up, my impression is that it helps some use cases but leaves others more ambiguous/unclear/unfortunate, which makes me lean towards rejecting it. Stefan ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
Stefan Behnel, 23.02.2014 19:51: Cython has typed assignments, so a straight forward idea would be to handle TypeErrors in assignments like this: cdef str s s = x except TypeError: str(x) Similar code in Python would be this: from array import array x = array('i', [1,2,3]) value = 123 x[0] = value except TypeError: int(value) However, I guess that would similarly counter the idea of exception handling in an *expression*, and the correct and non-ambiguous way to do this would be to spell out the try-except block. Stefan ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Feb 23, 2014 7:52 PM, Stefan Behnel stefan...@behnel.de wrote: Chris Angelico, 21.02.2014 04:15: Just as PEP 308 introduced a means of value-based conditions in an expression, this system allows exception-based conditions to be used as part of an expression. [...] This currently works:: lst = [1, 2, None, 3] value = lst[2] or No value The proposal adds this:: lst = [1, 2] value = lst[2] except IndexError: No value I see a risk of interfering with in-place assignment operators, e.g. x /= y except ZeroDivisionError: 1 might not do what one could expect, because (as I assume) it would behave differently from x = x / y except ZeroDivisionError: 1 Yes. Augmented assignment is still assignment, so a statement. The only way to parse that is as x /= (y except ZeroDivisionError: 1) and it'd be equivalent to x = x / (y except ZeroDivisionError: 1) (If the parentheses are mandatory that makes it easier to spot the difference.) I think that falls under the overly broad exception handling issue. If you want to include the assignment, you'll have to spell out the try-except block yourself. I find the difference in the two behaviours very unfortunate, though. This also reduces the scope of applicability somewhat. Cython has typed assignments, so a straight forward idea would be to handle TypeErrors in assignments like this: cdef str s s = x except TypeError: str(x) However, I guess that would similarly counter the idea of exception handling in an *expression*, and the correct and non-ambiguous way to do this would be to spell out the try-except block. Summing it up, my impression is that it helps some use cases but leaves others more ambiguous/unclear/unfortunate, which makes me lean towards rejecting it. Stefan ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/thomas%40python.org ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 02/23/2014 11:26 AM, Thomas Wouters wrote: On Feb 23, 2014 7:52 PM, Stefan Behnel stefan...@behnel.de mailto:stefan...@behnel.de wrote: Chris Angelico, 21.02.2014 04:15: Just as PEP 308 introduced a means of value-based conditions in an expression, this system allows exception-based conditions to be used as part of an expression. [...] This currently works:: lst = [1, 2, None, 3] value = lst[2] or No value The proposal adds this:: lst = [1, 2] value = lst[2] except IndexError: No value I see a risk of interfering with in-place assignment operators, e.g. x /= y except ZeroDivisionError: 1 might not do what one could expect, because (as I assume) it would behave differently from x = x / y except ZeroDivisionError: 1 Yes. Augmented assignment is still assignment, so a statement. The only way to parse that is as x /= (y except ZeroDivisionError: 1) Well, that is certainly not what I would have expected. I can also see how parentheses can help, but I still would like them optional. -- ~Ethan~ ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Mon, Feb 24, 2014 at 6:26 AM, Thomas Wouters tho...@python.org wrote: I see a risk of interfering with in-place assignment operators, e.g. x /= y except ZeroDivisionError: 1 might not do what one could expect, because (as I assume) it would behave differently from x = x / y except ZeroDivisionError: 1 Yes. Augmented assignment is still assignment, so a statement. The only way to parse that is as x /= (y except ZeroDivisionError: 1) and it'd be equivalent to x = x / (y except ZeroDivisionError: 1) (If the parentheses are mandatory that makes it easier to spot the difference.) I think that falls under the overly broad exception handling issue. If you want to include the assignment, you'll have to spell out the try-except block yourself. I find the difference in the two behaviours very unfortunate, though. Thomas's analysis is correct. It's not overly broad; in fact, what you have is an overly _narrow_ exception handler, catching a ZeroDivisionError from the evaluation of y only. ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
23.02.2014 19:51, Stefan Behnel wrote: I see a risk of interfering with in-place assignment operators, e.g. x /= y except ZeroDivisionError: 1 might not do what one could expect, because (as I assume) it would behave differently from x = x / y except ZeroDivisionError: 1 [snip] Please note that: x /= y if y else 0 also behaves differently from x = x / y if y else 0 Anyway, enclosing in parens would make that expicit and clear. Cheers. *j ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Mon, Feb 24, 2014 at 7:51 AM, Ethan Furman et...@stoneleaf.us wrote: Yes. Augmented assignment is still assignment, so a statement. The only way to parse that is as x /= (y except ZeroDivisionError: 1) Well, that is certainly not what I would have expected. I can see that you'd want to have that go back and redo the division with a second argument of 1, which'd look like this in statement form: try: x /= y except ZeroDivisionError: x /= 1 But, just like the decried error suppression technique, the second half of this is something that should instead be written pass. At very least, I'd say that an except-expression where one or other of its forms is better spelled pass is code smell, and at worst, I'd say it's a hint that the expression form might not even be what you think it is - as in this case. Remember, this is a scope-narrowing. Where previously you had to try/except entire statements, now you can try/except just one part of something. That means you won't catch errors in the actual assignment - which is usually a good thing - but it does affect augmented assignment. My recommendation: Just use try... except pass. I'm not trying to supplant the statement form :) ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 02/21/2014 10:57 PM, Stephen J. Turnbull wrote: Ethan Furman writes: On 02/21/2014 07:46 PM, Chris Angelico wrote: but not this: value = expr except Exception: default except Exception: default This should be the way it works. Nothing is gained in readability by turning a try with multiple except statements into an expression. Examples have been given several times. In general, if 'expr' is a function call, it may well have a couple of different ways to fail which imply different default values. interpolable = func(key) except TypeError: not a string: %s % key \ except KeyError: no such key: %s % key print(Some message that refers to '%s' % interpolable) versus try: interpolable = func(key) except TypeError: interpolable = not a string: %s % key except KeyError: interpolable = no such key: %s % key print(Some message that refers to '%s' % interpolable) I think the latter begs to be written as the former. Okay, that's the best example of that style I've seen so far (sorry, Chris, if something similar was in the PEP and I missed it). I will yield the point that something is gained -- still, I think it is a small something compared to converting a nested except statement into an expression, and if only allowing one or the other makes the whole thing simpler I vote for the nested excepts to be converted, not the already easily read multiple excepts. -- ~Ethan~ ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sat, 22 Feb 2014 15:57:02 +0900 Stephen J. Turnbull step...@xemacs.org wrote: try: interpolable = func(key) except TypeError: interpolable = not a string: %s % key except KeyError: interpolable = no such key: %s % key print(Some message that refers to '%s' % interpolable) I think that's a rare enough case, though (compared to the other idioms showcased in the PEP), that we needn't care about it. Regards Antoine. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Fri, 21 Feb 2014 09:37:29 -0800 Guido van Rossum gu...@python.org wrote: I'm put off by the ':' syntax myself (it looks to me as if someone forgot a newline somewhere) but 'then' feels even weirder (it's been hard-coded in my brain as meaning the first branch of an 'if'). Would 'else' work rather than 'then'? Regards Antoine. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sat, 22 Feb 2014 16:12:27 +0900 Stephen J. Turnbull step...@xemacs.org wrote: Note in support: I originally thought that get methods would be more efficient, but since Nick pointed out that haveattr is implemented by catching the exception (Yikes! LBYL implemented by using EAFP!), I assume that get methods also are (explicitly or implicitly) implemented that way. Well, the only way to know that a key (or attribute) exists is to do the lookup. What else would you suggest? And, yes, EAFP can avoid race conditions and the like (besides being more efficient with non-trivial keys). Regards Antoine. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Fri, 21 Feb 2014 19:49:20 -0700 Eric Snow ericsnowcurren...@gmail.com wrote: On Fri, Feb 21, 2014 at 7:07 PM, Victor Stinner victor.stin...@gmail.com wrote: Consider this example of a two-level cache:: for key in sequence: x = (lvl1[key] except KeyError: (lvl2[key] except KeyError: f(key))) # do something with x ... but I don't like when it is used to build complex expressions. This is true of any expression syntax, not just this proposal--though some expression syntax is more apt to be abused than others: you won't see many multiline int literals! ;) But this is precisely why Python has refrained from making everything an expression. For example, why assignements are not expressions. Regards Antoine. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sat, Feb 22, 2014 at 8:20 PM, Antoine Pitrou solip...@pitrou.net wrote: On Sat, 22 Feb 2014 16:12:27 +0900 Stephen J. Turnbull step...@xemacs.org wrote: Note in support: I originally thought that get methods would be more efficient, but since Nick pointed out that haveattr is implemented by catching the exception (Yikes! LBYL implemented by using EAFP!), I assume that get methods also are (explicitly or implicitly) implemented that way. Well, the only way to know that a key (or attribute) exists is to do the lookup. What else would you suggest? And, yes, EAFP can avoid race conditions and the like (besides being more efficient with non-trivial keys). Which means that, fundamentally, EAFP is the way to do it. So if PEP 463 expressions had existed from the beginning, hasattr() probably wouldn't have been written - people would just use an except-expression instead. ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sat, 22 Feb 2014 20:29:27 +1100 Chris Angelico ros...@gmail.com wrote: Which means that, fundamentally, EAFP is the way to do it. So if PEP 463 expressions had existed from the beginning, hasattr() probably wouldn't have been written - people would just use an except-expression instead. Really? hasattr() is much easier to write than the corresponding except-expression. Regards Antoine. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sat, Feb 22, 2014 at 8:58 PM, Antoine Pitrou solip...@pitrou.net wrote: On Sat, 22 Feb 2014 20:29:27 +1100 Chris Angelico ros...@gmail.com wrote: Which means that, fundamentally, EAFP is the way to do it. So if PEP 463 expressions had existed from the beginning, hasattr() probably wouldn't have been written - people would just use an except-expression instead. Really? hasattr() is much easier to write than the corresponding except-expression. But would it be sufficiently easier to justify the creation of a built-in? Imagine this were the other way around: we have except-expressions, but we don't have hasattr. Now someone comes onto python-ideas and says, Wouldn't it be nice if we had a hasattr() function to tell us whether something has an attribute or not. Considering that hasattr can be easily implemented using an except-expression, it would be unlikely to be considered worthy of a built-in. ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Fri, Feb 21, 2014 at 7:46 PM, Chris Angelico ros...@gmail.com wrote: On Sat, Feb 22, 2014 at 9:06 AM, Greg Ewing greg.ew...@canterbury.ac.nz wrote: Nick Coghlan wrote: On 21 February 2014 13:15, Chris Angelico ros...@gmail.com wrote: Generator expressions require parentheses, unless they would be strictly redundant. Ambiguities with except expressions could be resolved in the same way, forcing nested except-in-except trees to be correctly parenthesized I'd like to make the case that the PEP should adopt this as its default position. I generally agree, but I'd like to point out that this doesn't necessarily mean making the parenthesizing rules as strict as they are for generator expressions. The starting point for genexps is that the parens are part of the syntax, the same way that square brackets are part of the syntax of a list comprehension; we only allow them to be omitted in very special circumstances. On the other hand, I don't think there's any harm in allowing an except expression to stand on its own when there is no risk of ambiguity, e.g. foo = things[i] except IndexError: None should be allowed, just as we allow x = a if b else c and don't require x = (a if b else c) I'm inclined to agree with you. I fought against the mandated parens for a long time. Would be happy to un-mandate them, as long as there's no way for there to be ambiguity. Is CPython able to make an operator non-associative? That is, to allow these: value = expr except Exception: default value = (expr except Exception: default) except Exception: default value = expr except Exception: (default except Exception: default) but not this: value = expr except Exception: default except Exception: default ? Yes, although how to do it depends on what else 'default' and 'expr' can be. The simple answer is to make 'expr' and 'default' be subsets of expressions that don't include the 'except' expression themselves. Just like how in 'A if C else B', 'A' and 'C' do not include the 'if' syntax, but 'B' does: you need parentheses in '(a if c1 else b) if c2 else d' and 'a if (c1 if c3 else c2) else b' but not in 'a if c1 else b if c2 else d'. However, the question becomes what to do with 'lambda' and 'if-else'. Which of these should be valid (and mean what it means with the parentheses, which is how the PEP currently suggests it should be; ones without parenthesized alternatives are unambiguous, as far as I can tell.) 1. make_adder(x) except TypeError: lambda y: y + 0 2. lambda x: x + 0 except TypeError: 1 - lambda x: (x + 0 except TypeError: 1) 3. A if f(A) except TypeError: C else B 4. f(A1) except TypeError: A2 if C else B - f(A1) except TypeError: (A2 if C else B) 5. f(A1) except TypeError if C else ValueError: f(A2) 6. A if C else f(B) except TypeError: B - (A if C else f(B)) except TypeError: B 7. f(A) except E1(A) except E2(A): E2: E1 - f(A) except (E1(A) except E2(A): E2): E1 8. f(A) or f(B) except TypeError: f(C) - (f(A) or f(B)) except TypeError: f(C) 9. f(A) except TypeError: f(B) or f(C) - f(A) except TypeError: (f(B) or f(C)) 10. A == f(A) except TypeError: B - (A == f(A)) except TypeError: B 11. f(A) except TypeError: A == B - f(A) except TypeError: (A == B) 12. A + B except TypeError: C - (A + B) except TypeError: C 13. f(A) except TypeError: A + B - f(A) except TypeError: (A + B) #6 in particular and to some extent #4, #8 and #10 look wrong to me, so if they'd be allowed without parentheses perhaps the precedence of if-expr and except should be more nuanced. ('between lambda and ifexpr' is not really a sensible way to describe precedence anyway, since despite the insistence of the reference manual, the precedence of 'lambda' and 'ifexpr' is at best 'mixed': the grammar actually tries to match ifexpr first, but it works the way we all expect because 'lambda' is not an infix operator.) It's easy to disallow most of these (allowing only their parenthesized versions), the question is where to draw the line :) Some of these require a bit more work in the grammar, duplicating some of the grammar nodes, but it shouldn't be too bad. However, disallowing any infix operators in the 'default' expression means it'll still be valid, just mean something different; #9, for example, would be parsed as '(f(A) except TypeError: f(B)) or f(C)' if the 'default' expression couldn't be an or-expression. Disallowing it in the 'expr' expression wouldn't have that effect without parentheses. (FWIW, I have a working patch without tests that allows all of these, I'll upload it tonight so people can play with it. Oh, and FWIW, currently I'm +0 on the idea, -0 on the specific syntax.) -- Thomas Wouters tho...@python.org Hi! I'm an email virus! Think twice before sending your email to help me spread! ___ Python-Dev mailing list Python-Dev@python.org
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sat, 22 Feb 2014 21:09:07 +1100 Chris Angelico ros...@gmail.com wrote: On Sat, Feb 22, 2014 at 8:58 PM, Antoine Pitrou solip...@pitrou.net wrote: On Sat, 22 Feb 2014 20:29:27 +1100 Chris Angelico ros...@gmail.com wrote: Which means that, fundamentally, EAFP is the way to do it. So if PEP 463 expressions had existed from the beginning, hasattr() probably wouldn't have been written - people would just use an except-expression instead. Really? hasattr() is much easier to write than the corresponding except-expression. But would it be sufficiently easier to justify the creation of a built-in? Well, can you propose the corresponding except-expression? Regards Antoine. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
Antoine Pitrou writes: Well, the only way to know that a key (or attribute) exists is to do the lookup. What else would you suggest? Do the lookup at the C level (or whatever the implementation language is) and generate no exception, of course. That's what would make it possibly more efficient. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On sam., 2014-02-22 at 19:29 +0900, Stephen J. Turnbull wrote: Antoine Pitrou writes: Well, the only way to know that a key (or attribute) exists is to do the lookup. What else would you suggest? Do the lookup at the C level (or whatever the implementation language is) and generate no exception, of course. That's what would make it possibly more efficient. Let's see: - hasattr() does the lookup at the C level, and silences the AttributeError - dict.get() does the lookup at the C level, and doesn't generate an exception So apart from the minor inefficiency of generating and silencing the AttributeError, those functions already do what you suggest. Regards Antoine. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sat, Feb 22, 2014 at 9:17 PM, Antoine Pitrou solip...@pitrou.net wrote: On Sat, 22 Feb 2014 21:09:07 +1100 Chris Angelico ros...@gmail.com wrote: On Sat, Feb 22, 2014 at 8:58 PM, Antoine Pitrou solip...@pitrou.net wrote: On Sat, 22 Feb 2014 20:29:27 +1100 Chris Angelico ros...@gmail.com wrote: Which means that, fundamentally, EAFP is the way to do it. So if PEP 463 expressions had existed from the beginning, hasattr() probably wouldn't have been written - people would just use an except-expression instead. Really? hasattr() is much easier to write than the corresponding except-expression. But would it be sufficiently easier to justify the creation of a built-in? Well, can you propose the corresponding except-expression? It's hard to do hasattr itself without something messy - the best I can come up with is this: hasattr(x,y) - (x.y or True except AttributeError: False) but the bulk of uses of it are immediately before attempting to use the attribute. Many require multiple statements, so they'd be better done as a full try/except: cpython/python-gdb.py:1392: if not hasattr(self._gdbframe, 'select'): print ('Unable to select frame: ' 'this build of gdb does not expose a gdb.Frame.select method') return False self._gdbframe.select() return True becomes try: self._gdbframe.select() return True except AttributeError: print ('Unable to select frame: ' 'this build of gdb does not expose a gdb.Frame.select method') return False but others are clearly expressions in disguise: Lib/aifc.py:882: if hasattr(f, 'mode'): mode = f.mode else: mode = 'rb' becomes mode = (f.mode except AttributeError: 'rb') (In fact, I'm adding that one to the PEP's examples section.) Lib/cgi.py:145: if hasattr(fp,'encoding'): encoding = fp.encoding else: encoding = 'latin-1' becomes encoding = (fp.encoding except AttributeError: 'latin-1') Some could be done either way. If hasattr didn't exist, then this: Lib/argparse.py:597: if hasattr(params[name], '__name__'): params[name] = params[name].__name__ could be written instead as: params[name] = (params[name].__name__ except AttributeError: params[name]) which is similar length and doesn't require a built-in. Some are fairly clearly asking to be done as try/except, irrespective of this PEP: Lib/decimal.py:449: if hasattr(threading.current_thread(), '__decimal_context__'): del threading.current_thread().__decimal_context__ becomes try: del threading.current_thread().__decimal_context__ except AttributeError: pass (also ibid:476) Some are a bit of a mixture. Lib/dis.py:40: if hasattr(x, '__func__'): # Method x = x.__func__ if hasattr(x, '__code__'): # Function x = x.__code__ if hasattr(x, '__dict__'): # Class or module ... lots more code ... Could be done as try/except; first part could be done cleanly as an expression. This one's not quite as clean, but if hasattr didn't exist, this could be done either of two ways: Lib/fileinput.py:342: if hasattr(os, 'O_BINARY'): mode |= os.O_BINARY As an expression: mode |= (os.O_BINARY except AttributeError: 0) Or as a statement: try: mode |= os.O_BINARY except AttributeError: pass This one definitely would want to be changed, and is also going in the PEP: Lib/inspect.py:1350: return sys._getframe(1) if hasattr(sys, _getframe) else None becomes return (sys._getframe(1) except AttributeError: None) Lib/ntpath.py:558: # Win9x family and earlier have no Unicode filename support. supports_unicode_filenames = (hasattr(sys, getwindowsversion) and sys.getwindowsversion()[3] = 2) becomes supports_unicode_filenames = (sys.getwindowsversion()[3] = 2 except AttributeError: False) Another ternary-if LBYL that could become an expression-except EAFP: Lib/pdb.py:745: globs = self.curframe.f_globals if hasattr(self, 'curframe') else None becomes globs = (self.curframe.f_globals except AttributeError: None) although that will return None if self.curframe has no f_globals. Another nice easy one: Lib/pickletools.py:2227: if hasattr(data, tell): getpos = data.tell else: getpos = lambda: None becomes getpos = (data.tell except AttributeError: lambda: None) I could continue this theme, but behold, as Rose Maybud said, I have said enough. There are definitely cases where a local hasattr function could be useful, but if the code were already written to use try/except or an except-expression, there aren't many that would justify the creation of a builtin.
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sat, 22 Feb 2014 22:13:58 +1100 Chris Angelico ros...@gmail.com wrote: Well, can you propose the corresponding except-expression? It's hard to do hasattr itself without something messy - the best I can come up with is this: hasattr(x,y) - (x.y or True except AttributeError: False) But it's not the same. hasattr() returns a boolean, not an arbitrary value. try: self._gdbframe.select() return True except AttributeError: print ('Unable to select frame: ' 'this build of gdb does not expose a gdb.Frame.select method') return False But then you can't distinguish between a missing select method and an AttributeError raised by self._gdbframe.select() itself. but others are clearly expressions in disguise: Lib/aifc.py:882: if hasattr(f, 'mode'): mode = f.mode else: mode = 'rb' becomes mode = (f.mode except AttributeError: 'rb') Not significantly less wordy. Note you can already write: mode = getattr(f, 'mode', 'rb') which is more concise. (In fact, I'm adding that one to the PEP's examples section.) Lib/cgi.py:145: if hasattr(fp,'encoding'): encoding = fp.encoding else: encoding = 'latin-1' becomes encoding = (fp.encoding except AttributeError: 'latin-1') Same here: encoding = getattr(fp, 'encoding', 'latin-1') Some could be done either way. If hasattr didn't exist, then this: Lib/argparse.py:597: if hasattr(params[name], '__name__'): params[name] = params[name].__name__ could be written instead as: params[name] = (params[name].__name__ except AttributeError: params[name]) This makes a useless assignment if the attribute doesn't exist; it also spans a single expression over two lines instead of having two simple statements. It's definitely worse IMO. Some are fairly clearly asking to be done as try/except, irrespective of this PEP: Lib/decimal.py:449: if hasattr(threading.current_thread(), '__decimal_context__'): del threading.current_thread().__decimal_context__ becomes try: del threading.current_thread().__decimal_context__ except AttributeError: pass May hide a bug if threading.current_thread doesn't exist. Lib/inspect.py:1350: return sys._getframe(1) if hasattr(sys, _getframe) else None becomes return (sys._getframe(1) except AttributeError: None) May hide a bug if sys._getframe(1) itself raises AttributeError. (etc.) I could continue this theme, but behold, as Rose Maybud said, I have said enough. Yeah, none of these examples makes a convincing case that hasattr() is useless, IMO. Regards Antoine. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sat, Feb 22, 2014 at 10:27 PM, Antoine Pitrou solip...@pitrou.net wrote: Yeah, none of these examples makes a convincing case that hasattr() is useless, IMO. I'm not trying to make the case that it's useless. I'm trying to show that, if it didn't exist, all of these would be written some other way, and the case for its creation would not be terribly strong. It's definitely of value (and as you've shown in some of those cases, its proper use can narrow the exception-catching scope - a good thing), but not enough to be worth blessing with a built-in function. ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
Antoine Pitrou writes: On sam., 2014-02-22 at 19:29 +0900, Stephen J. Turnbull wrote: Antoine Pitrou writes: Well, the only way to know that a key (or attribute) exists is to do the lookup. What else would you suggest? Do the lookup at the C level (or whatever the implementation language is) and generate no exception, of course. That's what would make it possibly more efficient. Let's see: - hasattr() does the lookup at the C level, and silences the AttributeError - dict.get() does the lookup at the C level, and doesn't generate an exception So apart from the minor inefficiency of generating and silencing the AttributeError, those functions already do what you suggest. But that's precisely the inefficiency I'm referring to. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On sam., 2014-02-22 at 20:54 +0900, Stephen J. Turnbull wrote: Antoine Pitrou writes: On sam., 2014-02-22 at 19:29 +0900, Stephen J. Turnbull wrote: Antoine Pitrou writes: Well, the only way to know that a key (or attribute) exists is to do the lookup. What else would you suggest? Do the lookup at the C level (or whatever the implementation language is) and generate no exception, of course. That's what would make it possibly more efficient. Let's see: - hasattr() does the lookup at the C level, and silences the AttributeError - dict.get() does the lookup at the C level, and doesn't generate an exception So apart from the minor inefficiency of generating and silencing the AttributeError, those functions already do what you suggest. But that's precisely the inefficiency I'm referring to. Sure, but complaining about inefficiencies without asserting their significance is not very useful. Regards Antoine. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
Antoine Pitrou writes: On Sat, 22 Feb 2014 22:13:58 +1100 Chris Angelico ros...@gmail.com wrote: hasattr(x,y) - (x.y or True except AttributeError: False) But it's not the same. hasattr() returns a boolean, not an arbitrary value. I think he meant hasattr(x,y) - (x.y and True except AttributeError: False) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 2/22/2014 6:27 AM, Antoine Pitrou wrote: On Sat, 22 Feb 2014 22:13:58 +1100 Chris Angelico ros...@gmail.com wrote: Lib/inspect.py:1350: return sys._getframe(1) if hasattr(sys, _getframe) else None becomes return (sys._getframe(1) except AttributeError: None) May hide a bug if sys._getframe(1) itself raises AttributeError. return (sys._getframe except AttributeError: lambda i: None)(1) Assuming I have the syntax correct, and the bindings work this way, of course. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sat, Feb 22, 2014 at 11:14 PM, Stephen J. Turnbull step...@xemacs.org wrote: Antoine Pitrou writes: On Sat, 22 Feb 2014 22:13:58 +1100 Chris Angelico ros...@gmail.com wrote: hasattr(x,y) - (x.y or True except AttributeError: False) But it's not the same. hasattr() returns a boolean, not an arbitrary value. I think he meant hasattr(x,y) - (x.y and True except AttributeError: False) No, I meant 'or' to ensure that an attribute holding a false value doesn't come up false. But if you really want a boolean, just wrap it up in bool(). My main point, though, was that most usage of hasattr is probing just before something gets used - something like this: if hasattr(obj, attr): blah blah obj.attr else: maybe use a default or maybe do nothing Some cases could become except-expressions; others could become try/except statements. In each case, the loss would be small. I'm not saying hasattr should be removed, just that it wouldn't have a strong case if it didn't already exist. ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 22 Feb 2014 22:15, Stephen J. Turnbull step...@xemacs.org wrote: Antoine Pitrou writes: On Sat, 22 Feb 2014 22:13:58 +1100 Chris Angelico ros...@gmail.com wrote: hasattr(x,y) - (x.y or True except AttributeError: False) But it's not the same. hasattr() returns a boolean, not an arbitrary value. I think he meant hasattr(x,y) - (x.y and True except AttributeError: False) With PEP 463, the explicit equivalent of hasattr() would be something like : hasattr(x,y) - (bool(x.y) or True except AttributeError: False) The version Chris came up with was close, but as Antoine noted, didn't ensure the result was always exactly True or False. The translation isn't simple because we don't allow an else clause on the except expression (and I agree with this limitation), so the first expression needs to be one that will *evaluate* x.y, but ensure the result of the expression is True if no exception is thrown. However, as Chris noted in his reply, there are still cases where using hasattr makes more sense, so the fact it *can* be written as an except expression instead is a curiosity rather than anything with deep practical implications. Cheers, Nick. P.S. The fully general variant of else emulation under PEP 463: ((bool(EXPR) and False) or NO_EXC_RESULT except EXC: EXC_RESULT) Note: never actually use this, it's effectively unreadable ;) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/ncoghlan%40gmail.com ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Fri, Feb 21, 2014 at 8:41 PM, Greg Ewing greg.ew...@canterbury.ac.nzwrote: Ethan Furman wrote: On 02/21/2014 03:29 PM, Greg Ewing wrote: value = lst[2] except No value if IndexError It does read nicely, and is fine for the single, non-nested, case (which is probably the vast majority), but how would it handle nested exceptions? Hmmm, probably not very well, unless we define a except b if E1 except c if E2 to mean a except (b except c if E2) if E1 If E1 == E2, that could perhaps be abbreviated to a except b except c if E Or we could just decide that the nested case is going to be so rare it's not worth worrying about. +1 on not caring. Keep the expression for simple, obvious cases of a single exception type and fall back to the statement for fancier use (just like listcomps). The focus should be ease of expressiveness for a common pattern, not trying to convert tons of try/except statements into an expression just because we can. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sat, Feb 22, 2014 at 4:13 AM, Antoine Pitrou solip...@pitrou.net wrote: On Fri, 21 Feb 2014 09:37:29 -0800 Guido van Rossum gu...@python.org wrote: I'm put off by the ':' syntax myself (it looks to me as if someone forgot a newline somewhere) but 'then' feels even weirder (it's been hard-coded in my brain as meaning the first branch of an 'if'). Would 'else' work rather than 'then'? thing = stuff['key'] except KeyError else None That reads to me like the exception was silenced and only if there is no exception the None is returned, just like an 'else' clause on a 'try' statement. I personally don't mind the 'then' as my brain has been hard-coded to mean the first branch of a statement so it's looser than being explicitly associated with 'if' but with any multi-clause statement. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 22/02/2014 16:36, Brett Cannon wrote: On Sat, Feb 22, 2014 at 4:13 AM, Antoine Pitrou solip...@pitrou.net mailto:solip...@pitrou.net wrote: On Fri, 21 Feb 2014 09:37:29 -0800 Guido van Rossum gu...@python.org mailto:gu...@python.org wrote: I'm put off by the ':' syntax myself (it looks to me as if someone forgot a newline somewhere) but 'then' feels even weirder (it's been hard-coded in my brain as meaning the first branch of an 'if'). Would 'else' work rather than 'then'? thing = stuff['key'] except KeyError else None That reads to me like the exception was silenced and only if there is no exception the None is returned, just like an 'else' clause on a 'try' statement. I personally don't mind the 'then' as my brain has been hard-coded to mean the first branch of a statement so it's looser than being explicitly associated with 'if' but with any multi-clause statement. I read *except* as 'except if', and *:* as 'then' (often), so the main proposal reads naturally to me. I'm surprised to find others don't also, as that's the (only?) pronunciation that makes the familiar if-else and try-except constructs approximate English. Isn't adding a new keyword (*then*) likely to be a big deal? There is the odd example of its use as an identifier, just in our test code: http://hg.python.org/cpython/file/0695e465affe/Lib/test/test_epoll.py#l168 http://hg.python.org/cpython/file/0695e465affe/Lib/test/test_xmlrpc.py#l310 Jeff Allen ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 23 February 2014 02:29, Nick Coghlan ncogh...@gmail.com wrote: On 22 Feb 2014 22:15, Stephen J. Turnbull step...@xemacs.org wrote: Antoine Pitrou writes: Chris Angelico ros...@gmail.com wrote: hasattr(x,y) - (x.y or True except AttributeError: False) But it's not the same. hasattr() returns a boolean, not an arbitrary value. I think he meant hasattr(x,y) - (x.y and True except AttributeError: False) With PEP 463, the explicit equivalent of hasattr() would be something like : hasattr(x,y) - (bool(x.y) or True except AttributeError: False) That would work, but I think I'd prefer: hasattr(x,y) - bool(x.y or True except AttributeError: False) Makes it clearer IMO that the entire expression will always return a boolean. If exception expressions already existed in the language, I would think there would be a strong argument for a library function hasattr(), but probably not a builtin. Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
Stephen J. Turnbull step...@xemacs.org writes: Ethan Furman writes: On 02/21/2014 07:46 PM, Chris Angelico wrote: but not this: value = expr except Exception: default except Exception: default This should be the way it works. Nothing is gained in readability by turning a try with multiple except statements into an expression. Examples have been given several times. In general, if 'expr' is a function call, it may well have a couple of different ways to fail which imply different default values. interpolable = func(key) except TypeError: not a string: %s % key \ except KeyError: no such key: %s % key print(Some message that refers to '%s' % interpolable) versus try: interpolable = func(key) except TypeError: interpolable = not a string: %s % key except KeyError: interpolable = no such key: %s % key print(Some message that refers to '%s' % interpolable) I think the following suggestion from elsewhere in the thread would look even better in this case: interpolable = func(key) except (TypeError: not a string: %s % key, KeyError: no such key: %s % key) print(Some message that refers to '%s' % interpolable) It does not require the backslash, it is shorter, and it can still be chained: interpolable = func(key) except (TypeError: not a string: %s % key, KeyError: defaults[key] except (KeyError: no such key: %s % key)) print(Some message that refers to '%s' % interpolable) Best, -Nikolaus -- Encrypted emails preferred. PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6 02CF A9AD B7F8 AE4E 425C »Time flies like an arrow, fruit flies like a Banana.« ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
Antoine Pitrou writes: Sure, but complaining about inefficiencies without asserting their significance is not very useful. Since you completely missed the point of my post, I'll explain. I was in no way complaining about inefficiencies. My point was precisely the opposite: to the extent that most 'get' methods would be implemented in Python, even the minor inefficiency of creating and suppressing a useless exception can't be avoided with the LBYL of a get method, because haveattr itself is implemented by generating and suppressing an exception. I know that it's not a big deal[1], but it did help swing me to positive on this PEP. Footnotes: [1] If it were, somebody would have reimplemented haveattr to avoid generating an exception. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sat, Feb 22, 2014 at 2:08 AM, Thomas Wouters tho...@python.org wrote: (FWIW, I have a working patch without tests that allows all of these, I'll upload it tonight so people can play with it. Oh, and FWIW, currently I'm +0 on the idea, -0 on the specific syntax.) http://bugs.python.org/issue20739 is the patch. -- Thomas Wouters tho...@python.org Hi! I'm an email virus! Think twice before sending your email to help me spread! ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sun, Feb 23, 2014 at 11:00 AM, Thomas Wouters tho...@python.org wrote: On Sat, Feb 22, 2014 at 2:08 AM, Thomas Wouters tho...@python.org wrote: (FWIW, I have a working patch without tests that allows all of these, I'll upload it tonight so people can play with it. Oh, and FWIW, currently I'm +0 on the idea, -0 on the specific syntax.) http://bugs.python.org/issue20739 is the patch. Thanks! You make a comment about precedence. When I wrote that up, it was basically just that seems about right; whether it's equal to lambda, equal to if/else, above both, below both, or in between, is free to be tweaked according to what makes sense. Nobody has to date discussed the exact precedence order, so feel free to tweak it for the benefit of implementation. ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 2014-02-23 00:09, Chris Angelico wrote: On Sun, Feb 23, 2014 at 11:00 AM, Thomas Wouters tho...@python.org wrote: On Sat, Feb 22, 2014 at 2:08 AM, Thomas Wouters tho...@python.org wrote: (FWIW, I have a working patch without tests that allows all of these, I'll upload it tonight so people can play with it. Oh, and FWIW, currently I'm +0 on the idea, -0 on the specific syntax.) http://bugs.python.org/issue20739 is the patch. Thanks! You make a comment about precedence. When I wrote that up, it was basically just that seems about right; whether it's equal to lambda, equal to if/else, above both, below both, or in between, is free to be tweaked according to what makes sense. Nobody has to date discussed the exact precedence order, so feel free to tweak it for the benefit of implementation. My feeling is that catching exceptions should have a lower precedence than the other parts of an expression, but higher than comma, so: A if C else B except E: D would be parsed as: (A if C else B) except E: D I think that's because it's kind of replacing: try: _ = expr except E: _ = D with the try..except enclosing the expression. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 23 February 2014 11:11, MRAB pyt...@mrabarnett.plus.com wrote: On 2014-02-23 00:09, Chris Angelico wrote: On Sun, Feb 23, 2014 at 11:00 AM, Thomas Wouters tho...@python.org wrote: On Sat, Feb 22, 2014 at 2:08 AM, Thomas Wouters tho...@python.org wrote: (FWIW, I have a working patch without tests that allows all of these, I'll upload it tonight so people can play with it. Oh, and FWIW, currently I'm +0 on the idea, -0 on the specific syntax.) http://bugs.python.org/issue20739 is the patch. Thanks! You make a comment about precedence. When I wrote that up, it was basically just that seems about right; whether it's equal to lambda, equal to if/else, above both, below both, or in between, is free to be tweaked according to what makes sense. Nobody has to date discussed the exact precedence order, so feel free to tweak it for the benefit of implementation. My feeling is that catching exceptions should have a lower precedence than the other parts of an expression, but higher than comma, so: A if C else B except E: D would be parsed as: (A if C else B) except E: D I think that's because it's kind of replacing: try: _ = expr except E: _ = D with the try..except enclosing the expression. Note that mandatory parentheses means we can duck the precedence question entirely, which I count as another point in favour of requiring them :) Cheers, Nick. -- Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 21 February 2014 13:15, Chris Angelico ros...@gmail.com wrote: PEP: 463 Title: Exception-catching expressions Version: $Revision$ Last-Modified: $Date$ Author: Chris Angelico ros...@gmail.com Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 15-Feb-2014 Python-Version: 3.5 Post-History: 16-Feb-2014, 21-Feb-2014 Abstract Just as PEP 308 introduced a means of value-based conditions in an expression, this system allows exception-based conditions to be used as part of an expression. Great work on this Chris - this is one of the best researched and justified Python syntax proposals I've seen :) Open Issues === Parentheses around the entire expression Generator expressions require parentheses, unless they would be strictly redundant. Ambiguities with except expressions could be resolved in the same way, forcing nested except-in-except trees to be correctly parenthesized and requiring that the outer expression be clearly delineated. `Steven D'Aprano elaborates on the issue.`__ __ https://mail.python.org/pipermail/python-ideas/2014-February/025647.html I'd like to make the case that the PEP should adopt this as its default position. My rationale is mainly that if we start by requiring the parentheses, it's pretty straightforward to take that requirement away in specific cases later, as well as making it easier to introduce multiple except clauses if that ever seems necessary. However, if we start without the required parentheses, that's it - we can't introduce a requirement for parentheses later if we decide the bare form is too confusing in too many contexts, and there's plenty of potential for such confusion. In addition to the odd interactions with other uses of the colon as a marker in the syntax, including suite headers, lambdas and function annotations, omitting the parentheses makes it harder to decide which behaviour was intended in ambiguous cases, while the explicit parentheses would force the writer to be clear which one they meant. Consider: x = get_value() except NotFound: foo is not None There are two plausible interpretations of that: x = (get_value() except NotFound: foo) is not None x = get_value() except NotFound: (foo is not None) With the proposed precedence in the PEP (which I agree with), the latter is the correct interpretation, but that's not at all obvious to the reader - they would have to just know that's the way it works. By contrast, if the parentheses are required, then the spelling would have to be one of the following to be legal: x = (get_value() except NotFound: foo is not None) x = (get_value() except NotFound: foo) is not None Which means the : and the closing ) nicely bracket the fallback value in both cases and make the author's intent relatively clear. The required parentheses also help in the cases where there is a nearby colon with a different meaning: if check() except Exception: False: ... if (check() except Exception: False): ... lambda x: calculate(x) except Exception: None lambda x: (calculate(x) except Exception: None) def f(a: OS dependent = os_defaults[os.name] except KeyError: None): pass def f(a: OS dependent = (os_defaults[os.name] except KeyError: None)): pass Rather than making people consider do I need the parentheses in this case or not?, adopting the genexp rule makes it simple: yes, you need them, because the compiler will complain if you leave them out. Retrieving a message from either a cache or the internet, with auth check:: logging.info(Message shown to user: %s,((cache[k] except LookupError: (backend.read(k) except OSError: 'Resource not available') ) if check_permission(k) else 'Access denied' ) except BaseException: This is like a bare except clause) I don't think taking it all the way to one expression shows the new construct in the best light. Keeping this as multiple statements assigning to a temporary variable improves the readability quite a bit: if not check_permission(k): msg = 'Access denied' else: msg = (cache[k] except LookupError: None) if msg is None: msg = (backend.read(k) except OSError: 'Resource not available') logging.info(Message shown to user: %s, msg) I would also move the bare except clause equivalent out to a separate example. Remember, you're trying to convince people to *like* the PEP, not scare them away with the consequences of what happens when people try to jam too much application logic into a single statement. While we're admittedly giving people another tool to help them win obfuscated Python contests, we don't have to *encourage* them :) try: if check_permission(k): try: _ = cache[k] except LookupError: try: _ = backend.read(k)
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 21 February 2014 11:35, Nick Coghlan ncogh...@gmail.com wrote: Just as PEP 308 introduced a means of value-based conditions in an expression, this system allows exception-based conditions to be used as part of an expression. Great work on this Chris - this is one of the best researched and justified Python syntax proposals I've seen :) Agreed - given the number of differing opinions on python-ideas, it's particularly impressive how well the debate was conducted too. Paul ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Fri, Feb 21, 2014 at 10:35 PM, Nick Coghlan ncogh...@gmail.com wrote: On 21 February 2014 13:15, Chris Angelico ros...@gmail.com wrote: PEP: 463 Title: Exception-catching expressions Great work on this Chris - this is one of the best researched and justified Python syntax proposals I've seen :) It is? Wow... I'm not sure what that says about other syntax proposals. This is one week's python-ideas discussion plus one little script doing analysis on the standard library. Hardly PhD level research :) Parentheses around the entire expression Generator expressions require parentheses, unless they would be strictly redundant. Ambiguities with except expressions could be resolved in the same way, forcing nested except-in-except trees to be correctly parenthesized and requiring that the outer expression be clearly delineated. `Steven D'Aprano elaborates on the issue.`__ __ https://mail.python.org/pipermail/python-ideas/2014-February/025647.html I'd like to make the case that the PEP should adopt this as its default position. My rationale is mainly that if we start by requiring the parentheses, it's pretty straightforward to take that requirement away in specific cases later, as well as making it easier to introduce multiple except clauses if that ever seems necessary. However, if we start without the required parentheses, that's it - we can't introduce a requirement for parentheses later if we decide the bare form is too confusing in too many contexts, and there's plenty of potential for such confusion. If once the parens are made mandatory, they'll most likely stay mandatory forever - I can't imagine there being any strong impetus to change the language to make them optional. The required parentheses also help in the cases where there is a nearby colon with a different meaning: if check() except Exception: False: ... if (check() except Exception: False): People can already write: if (x if y else z): without the parens, and it works. Readability suffers when the same keyword is used twice (here if rather than the colon, but same difference), yet the parens are considered optional. Python is a language that, by and large, lacks syntactic salt; style guides are free to stipulate more, but the language doesn't make demands. I would strongly *recommend* using parens in all the cases you've shown, especially lambda: lambda x: calculate(x) except Exception: None lambda x: (calculate(x) except Exception: None) as it would otherwise depend on operator precedence; but mandating them feels to me like demanding readability. def f(a: OS dependent = os_defaults[os.name] except KeyError: None): pass def f(a: OS dependent = (os_defaults[os.name] except KeyError: None)): pass Ehh, that one's a mess. I'd be looking at breaking out the default: default = os_defaults[os.name] except KeyError: None def f(a: OS dependent = default): pass with possibly some better name than 'default'. The one-liner is almost 80 characters long without indentation and with very short names. But if it's okay to wrap it, that would work without the parens: def f( a: OS dependent = os_defaults[os.name] except KeyError: None, another_arg ., more, args .., ): pass Clarity is maintained by judicious placement of newlines just as much as by parentheses. Rather than making people consider do I need the parentheses in this case or not?, adopting the genexp rule makes it simple: yes, you need them, because the compiler will complain if you leave them out. Yes, that is a reasonable line of argument. On the other hand, there's no demand for parens when you mix and and or: x or y and z I'd wager more than half of Python programmers would be unable to say for sure which would be evaluated first. The compiler could have been written to reject this (by placing and and or at the same precedence and having no associativity - I'm not sure if the current lexer in CPython can do that, but it's certainly not conceptually inconceivable), but a decision was made to make this legal. Retrieving a message from either a cache or the internet, with auth check:: logging.info(Message shown to user: %s,((cache[k] except LookupError: (backend.read(k) except OSError: 'Resource not available') ) if check_permission(k) else 'Access denied' ) except BaseException: This is like a bare except clause) I don't think taking it all the way to one expression shows the new construct in the best light. Keeping this as multiple statements assigning to a temporary variable improves the readability quite a bit: Yeah, good point. I tried to strike a balance between simple and complex examples, but it's hard to judge. I would also move the bare except clause equivalent out to a separate example. Remember, you're trying to convince people to *like* the PEP, not scare them away with
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Fri, Feb 21, 2014 at 11:37 PM, Paul Moore p.f.mo...@gmail.com wrote: On 21 February 2014 11:35, Nick Coghlan ncogh...@gmail.com wrote: Just as PEP 308 introduced a means of value-based conditions in an expression, this system allows exception-based conditions to be used as part of an expression. Great work on this Chris - this is one of the best researched and justified Python syntax proposals I've seen :) Agreed - given the number of differing opinions on python-ideas, it's particularly impressive how well the debate was conducted too. On that subject, I'd like to thank everyone involved in the python-ideas discussion, and particularly Steven D'Aprano, Rob Cliffe, and Andrew Barnert; it was an amazingly productive thread, getting to nearly four hundred emails before seriously meandering. And even then, it mostly just started looping back on itself, which isn't surprising given that it was so long - anyone not majorly invested in the topic won't have read every single post. ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 21 February 2014 22:42, Chris Angelico ros...@gmail.com wrote: It'd be a backward-incompatible change, but it's more likely to be what people expect. The general assumption of with ... as ... is that the thing should be used inside the block, and should be finished with when you exit the block, so having the name valid only inside the block does make sense. That's a completely separate proposal. But suppose that were to happen, and to not require a closure. It would then make good sense to be able to capture an exception inside an expression - and it could be done without breaking anything. So, if it is to be rejected, I'd say it's on the technical grounds that it would require a closure in CPython, and that a closure is incompatible with the current proposal. Does that sound right? (It's also not a huge loss, since it's almost unused. But it's an incompatibility between statement and expression form.) It's probably OK to leave it in the deferred section and just note the difficulty of implementing it in a backwards compatible way, since we're *not* going to be introducing a closure. Python 3 except clauses are already a bit weird anyway, since they do an implicit delete at the end, but only if the except clause is actually triggered: e = Hello try: ... 1/0 ... except ZeroDivisionError as e: ... pass ... e Traceback (most recent call last): File stdin, line 1, in module NameError: name 'e' is not defined e = Hello try: ... pass ... except Exception as e: ... pass ... e 'Hello' Cheers, Nick. -- Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Fri, 21 Feb 2014 14:15:59 +1100 Chris Angelico ros...@gmail.com wrote: A number of functions and methods have parameters which will cause them to return a specified value instead of raising an exception. The current system is ad-hoc and inconsistent, and requires that each function be individually written to have this functionality; not all support this. While I sympathize with the motivation, I really don't like the end result: lst = [1, 2] value = lst[2] except IndexError: No value is too much of a break from the usual stylistic conventions, and looks like several statements were stuffed on a single line. In other words, the gain in concision is counterbalanced by a loss in readability, a compromise which doesn't fit in Python's overall design principles. (compare with with, which solves actual readability issues due to the distance between the try and the finally clause, and also promotes better resource management) So -0.5 from me. Regards Antoine. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 21 February 2014 22:42, Chris Angelico ros...@gmail.com wrote: People can already write: if (x if y else z): without the parens, and it works. Readability suffers when the same keyword is used twice (here if rather than the colon, but same difference), yet the parens are considered optional. Python is a language that, by and large, lacks syntactic salt; style guides are free to stipulate more, but the language doesn't make demands. I would strongly *recommend* using parens in all the cases you've shown, especially lambda: lambda x: calculate(x) except Exception: None lambda x: (calculate(x) except Exception: None) as it would otherwise depend on operator precedence; but mandating them feels to me like demanding readability. Right, that's why my main motivation for this suggestion is the one relating to keeping future options open. If the parentheses are optional, than adding multiple except clauses latter isn't possible, since this would already be valid, but mean something different: expr except Exception1: default1 except Exception2: default2 The deferral currently has this snippet: In order to ensure compatibility with future versions, ensure that any consecutive except operators are parenthesized to guarantee the interpretation you expect. That's not a reasonable expectation - either the parentheses have to be mandatory as part of the deferral, or else multiple except clause support needs to be listed as rejected rather than deferred. Cheers, Nick. -- Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
My 2 cents worth: On 21/02/2014 12:42, Chris Angelico wrote: On Fri, Feb 21, 2014 at 10:35 PM, Nick Coghlan ncogh...@gmail.com wrote: Great work on this Chris - this is one of the best researched and justified Python syntax proposals I've seen :) Hear, hear! (Praise from the praiseworthy is praise indeed - Tolkien.) Small point: in one of your examples you give a plug for the PEP note the DRY improvement. I would suggest that similarly perhaps in your Lib/tarfile.py:2198 example you point out the increase in readability due to the 2 lines lining up in your Lib/ipaddress.py:343 example you point out that the new form is probably an improvement (i.e. probably closer to the author's intention) as it will NOT catch an AttributeError evaluating ips.append (this would matter e.g. if append were mis-spelt). YOU are clearly aware of this but it would often escape the casual reader. Retrieving a message from either a cache or the internet, with auth check:: logging.info(Message shown to user: %s,((cache[k] except LookupError: (backend.read(k) except OSError: 'Resource not available') ) if check_permission(k) else 'Access denied' ) except BaseException: This is like a bare except clause) I don't think taking it all the way to one expression shows the new construct in the best light. Keeping this as multiple statements assigning to a temporary variable improves the readability quite a bit: I agree, it looks scary (too many branches in one statement). The shorter the example, the more convincing. Yeah, good point. I tried to strike a balance between simple and complex examples, but it's hard to judge. Capturing the exception object -- An examination of the Python standard library shows that, while the use of 'as' is fairly common (occurring in roughly one except clause in five), it is extremely *uncommon* in the cases which could logically be converted into the expression form. Its few uses can simply be left unchanged. Consequently, in the interests of simplicity, the 'as' clause is not included in this proposal. A subsequent Python version can add this without breaking any existing code, as 'as' is already a keyword. We can't defer this one - if we don't implement it now, we should reject it as a future addition. The reason we can't defer it is [ chomped for brevity ] So I think it makes more sense to reject this subproposal outright - it makes the change more complex and make the handling of the common case worse, for the sake of something that will almost never be an appropriate thing to do. Thanks for looking into this Nick. I confess I don't entirely understand the technical argument (my understanding breaks down at the subexpressions can't see the class level variables, but I don't want to waste anybody's time expecting an explanation, I can always look into it myself) but I accept that there is a good reason for disallowing 'as' and its usage would be rare, so I will (slightly regretfully) wave it goodbye. So, if it is to be rejected, I'd say it's on the technical grounds that it would require a closure in CPython, and that a closure is incompatible with the current proposal. Does that sound right? It does to me FWIW. (It's also not a huge loss, since it's almost unused. But it's an incompatibility between statement and expression form.) ChrisA Assuming the PEP is accepted (not a trivial assumption!) I hope that at some stage allowing multiple except clauses (to trap different exceptions raised by the original expression) will be reinstated. But I have to accept that it would be rarely used. To my mind the real unsung hero of this story is the existing try ... except ... finally syntax and its flexibility. In my code base there were a few hundred of these, but just over a dozen where the new syntax would be appropriate. (Hope I'm not starting to argue against the PEP!) Rob Cliffe ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/rob.cliffe%40btinternet.com - No virus found in this message. Checked by AVG - www.avg.com Version: 2012.0.2247 / Virus Database: 3705/6611 - Release Date: 02/20/14 ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 22 February 2014 00:03, Eli Bendersky eli...@gmail.com wrote: On Thu, Feb 20, 2014 at 7:15 PM, Chris Angelico ros...@gmail.com wrote: PEP: 463 Title: Exception-catching expressions Version: $Revision$ Last-Modified: $Date$ Author: Chris Angelico ros...@gmail.com Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 15-Feb-2014 Python-Version: 3.5 Post-History: 16-Feb-2014, 21-Feb-2014 Abstract Just as PEP 308 introduced a means of value-based conditions in an expression, this system allows exception-based conditions to be used as part of an expression. Chris, while I also commend you for the comprehensive PEP, I'm -1 on the proposal, for two main reasons: 1. Many proposals suggest new syntax to gain some succinctness. Each has to be judged for its own merits, and in this case IMHO the cons eclipse the pros. I don't think this will save a lot of code in a typical well-structured program - maybe a few lines out of hundreds. On the other hand, it adds yet another syntax to remember and understand, which is not the Pythonic way. 2. Worse, this idea subverts exceptions to control flow, which is not only un-Pythonic but also against the accepted practices of programming in general. Here, the comparison to PEP 308 is misguided. PEP 308, whatever syntax it adds, still remains within the domain of normal control flow. PEP 463, OTOH, makes it deliberately easy to make exceptions part of non-exceptional code, encouraging very bad programming practices. Neither of these objections addresses the problems with the status quo, though: - the status quo encourages overbroad exception handling (as illustrated by examples in the PEP) - the status quo encourages an ad hoc approach to hiding exception handling inside functions PEP 308 was accepted primarily because the and/or hack was a bug magnet. The status quo for exception handling is both a bug magnet (due to overbroad exception handlers), and a cause of creeping complexity in API design (as more and more APIs, both in the standard library and elsewhere, acquire ways to request implicit exception handling). That's why the comparison to PEP 308 is appropriate: it's less about making the language better directly, and more about deciding the consequences of not having it are no longer acceptable. Cheers, Nick. -- Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Fri, Feb 21, 2014 at 8:52 AM, Antoine Pitrou solip...@pitrou.net wrote: On Fri, 21 Feb 2014 14:15:59 +1100 Chris Angelico ros...@gmail.com wrote: A number of functions and methods have parameters which will cause them to return a specified value instead of raising an exception. The current system is ad-hoc and inconsistent, and requires that each function be individually written to have this functionality; not all support this. While I sympathize with the motivation, I really don't like the end result: lst = [1, 2] value = lst[2] except IndexError: No value is too much of a break from the usual stylistic conventions, and looks like several statements were stuffed on a single line. In other words, the gain in concision is counterbalanced by a loss in readability, a compromise which doesn't fit in Python's overall design principles. (compare with with, which solves actual readability issues due to the distance between the try and the finally clause, and also promotes better resource management) While I like the general concept, I agree that it looks too much like a crunched statement; the use of the colon is a non-starter for me. I'm sure I'm not the only one whose brain has been trained to view a colon in Python to mean statement, period. This goes against that syntactic practice and just doesn't work for me. I'm -1 with the current syntax, but it can go into the + range if a better syntax can be chosen. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Fri, Feb 21, 2014 at 6:28 AM, Nick Coghlan ncogh...@gmail.com wrote: On 22 February 2014 00:03, Eli Bendersky eli...@gmail.com wrote: On Thu, Feb 20, 2014 at 7:15 PM, Chris Angelico ros...@gmail.com wrote: PEP: 463 Title: Exception-catching expressions Version: $Revision$ Last-Modified: $Date$ Author: Chris Angelico ros...@gmail.com Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 15-Feb-2014 Python-Version: 3.5 Post-History: 16-Feb-2014, 21-Feb-2014 Abstract Just as PEP 308 introduced a means of value-based conditions in an expression, this system allows exception-based conditions to be used as part of an expression. Chris, while I also commend you for the comprehensive PEP, I'm -1 on the proposal, for two main reasons: 1. Many proposals suggest new syntax to gain some succinctness. Each has to be judged for its own merits, and in this case IMHO the cons eclipse the pros. I don't think this will save a lot of code in a typical well-structured program - maybe a few lines out of hundreds. On the other hand, it adds yet another syntax to remember and understand, which is not the Pythonic way. 2. Worse, this idea subverts exceptions to control flow, which is not only un-Pythonic but also against the accepted practices of programming in general. Here, the comparison to PEP 308 is misguided. PEP 308, whatever syntax it adds, still remains within the domain of normal control flow. PEP 463, OTOH, makes it deliberately easy to make exceptions part of non-exceptional code, encouraging very bad programming practices. Neither of these objections addresses the problems with the status quo, though: - the status quo encourages overbroad exception handling (as illustrated by examples in the PEP) - the status quo encourages an ad hoc approach to hiding exception handling inside functions I think the PEP, and your reply, focuses too much on one single status quo situation, which is the dict.get-like usage. However, the PEP does not propose a narrow solution - it proposes a significant change in the way expressions may be written and exceptions may be caught, and thus opens a can of worms. Even if the status quo will be made better by it, and even this I'm not sure about (*), many many other possibilities of bad code open up. (*) IMHO it's better to hide these exceptions inside well defined functions -- because dict.get tells me it's the normal code flow, not the exceptional code flow. On the other hand, the syntax proposed herein tells me - yeah it's the exceptional code flow, but let me merge it into the normal code flow for you. This goes against anything I understand about how exceptions should and should not be used. Eli PEP 308 was accepted primarily because the and/or hack was a bug magnet. The status quo for exception handling is both a bug magnet (due to overbroad exception handlers), and a cause of creeping complexity in API design (as more and more APIs, both in the standard library and elsewhere, acquire ways to request implicit exception handling). That's why the comparison to PEP 308 is appropriate: it's less about making the language better directly, and more about deciding the consequences of not having it are no longer acceptable. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 22 February 2014 00:37, Eli Bendersky eli...@gmail.com wrote: This goes against anything I understand about how exceptions should and should not be used. I think you're thinking of a language that isn't Python - we use exceptions for control flow all over the place (it's how hasattr() is *defined*, for example). Cheers, Nick. -- Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Fri, Feb 21, 2014 at 6:46 AM, Nick Coghlan ncogh...@gmail.com wrote: On 22 February 2014 00:37, Eli Bendersky eli...@gmail.com wrote: This goes against anything I understand about how exceptions should and should not be used. I think you're thinking of a language that isn't Python - we use exceptions for control flow all over the place (it's how hasattr() is *defined*, for example). No, it is Python I'm thinking about. As I mentioned in the reply to Brett's message, I see a difference between allowing exceptions on expression level and statement level. The latter is less likely to be abused. Once you add exceptions into expressions, all bets are off. For instance, it is sometime non-trivial to know which exceptions some function may throw. When you write a try...raise statement, you think hard about covering all the bases. In an expression you're unlikely to, which opens up a lot of possibilities for bugs. Again, please stop focusing just on the list[index] case -- the proposal adds a new significant feature to the language that can (and thus will) be used in a variety of scenarios. Eli ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sat, 22 Feb 2014 00:28:01 +1000 Nick Coghlan ncogh...@gmail.com wrote: Neither of these objections addresses the problems with the status quo, though: - the status quo encourages overbroad exception handling (as illustrated by examples in the PEP) I don't get this. Using the proper exception class in a try...except suite is no more bothersome than using the proper exception class in this newly-proposed construct. Regards Antoine. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On 22 February 2014 00:44, Eli Bendersky eli...@gmail.com wrote: True, but at least you still have to explicitly try...except... which takes a toll on the code so isn't taken lightly. Adding except into expressions, I fear, will proliferate this usage much more. The same fears were raised regarding conditional expressions, and they'll be dealt with the same way: style guides and code review. That's also why the examples part of the PEP is so important, though: this is about providing a tool to *improve* readability in the cases where it applies, without significantly increasing the cognitive burden of the language. One example not mentioned in the PEP is that text.find(substr) would become just a shorthand for text.index(substr) except ValueError: -1, but the latter has the benefit that you can substitute None instead, which avoids the trap where -1 is a valid subscript for the string (but doesn't give you the answer you want). Cheers, Nick. -- Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sat, Feb 22, 2014 at 12:53 AM, Nick Coghlan ncogh...@gmail.com wrote: On 21 February 2014 22:42, Chris Angelico ros...@gmail.com wrote: People can already write: if (x if y else z): without the parens, and it works. Readability suffers when the same keyword is used twice (here if rather than the colon, but same difference), yet the parens are considered optional. Python is a language that, by and large, lacks syntactic salt; style guides are free to stipulate more, but the language doesn't make demands. I would strongly *recommend* using parens in all the cases you've shown, especially lambda: lambda x: calculate(x) except Exception: None lambda x: (calculate(x) except Exception: None) as it would otherwise depend on operator precedence; but mandating them feels to me like demanding readability. Right, that's why my main motivation for this suggestion is the one relating to keeping future options open. If the parentheses are optional, than adding multiple except clauses latter isn't possible, since this would already be valid, but mean something different: expr except Exception1: default1 except Exception2: default2 The deferral currently has this snippet: In order to ensure compatibility with future versions, ensure that any consecutive except operators are parenthesized to guarantee the interpretation you expect. That's not a reasonable expectation - either the parentheses have to be mandatory as part of the deferral, or else multiple except clause support needs to be listed as rejected rather than deferred. I've spent the better part of the last hour debating this in my head. It's basically a question of simplicity versus future flexibility: either keep the syntax clean and deny the multiple-except-clause option, or mandate the parens and permit it. The first option has, in my own head, the stronger case - this is designed for simplicity, and it wouldn't be that big a deal to completely reject multiple except clauses and simply require that the ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 463: Exception-catching expressions
On Sat, Feb 22, 2014 at 1:59 AM, Chris Angelico ros...@gmail.com wrote: I've spent the better part of the last hour debating this in my head. It's basically a question of simplicity versus future flexibility: either keep the syntax clean and deny the multiple-except-clause option, or mandate the parens and permit it. The first option has, in my own head, the stronger case - this is designed for simplicity, and it wouldn't be that big a deal to completely reject multiple except clauses and simply require that the Oops, hit the wrong key and sent that half-written. ... and simply require that the statement form be used. But the whelming opinion of python-dev seems to be in favour of the parens anyway, and since they give us the possibility of future expansion effectively for free, I've gone that way. Parens are now required; the syntax is: value = (expr except Exception: default) and, as per genexp rules, redundant parens can be omitted: print(lst[i] except IndexError: Out of bounds) ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com