',' precedence in documentation

Hi folks, over on the pygr list, we were recently discussing a mildly confusing edit I made: assert 'seq1' in self.db, self.db.keys() This was interpreted by someone as being assert 'seq1' in (self.db, self.db.keys()) which is very different from the actual meaning, assert ('seq1' in self.db), self.db.keys() where 'self.db.keys()' serves as the message to be printed out when the assertion fails. Apart from questions of why I was apparently out to confuse people with this edit, the question of ',' precedence came up. Looking at http://docs.python.org/ref/summary.html there's no mention of ',' binding and tuple creation vs the other operators. I'm not really sure how to think of it but it seems like this is something that could be cleared up in the docs with a brief note somewhere. Thoughts? cheers, --titus -- C. Titus Brown, ctb@msu.edu

C. Titus Brown wrote:
over on the pygr list, we were recently discussing a mildly confusing edit I made:
assert 'seq1' in self.db, self.db.keys()
This was interpreted by someone as being
assert 'seq1' in (self.db, self.db.keys())
which is very different from the actual meaning,
assert ('seq1' in self.db), self.db.keys()
where 'self.db.keys()' serves as the message to be printed out when the assertion fails. Apart from questions of why I was apparently out to confuse people with this edit, the question of ',' precedence came up. Looking at
http://docs.python.org/ref/summary.html
there's no mention of ',' binding and tuple creation vs the other operators.
A bare "," is part of the "expression list" syntax; it's not an operator: http://docs.python.org/ref/exprlists.html You have to look at the statement descriptions to find out whether a statement wants an expression or an expression list (e.g. "return" takes an expression list, while "assert" takes two expressions, not two expression lists). </F>

On Sun, Sep 14, 2008 at 12:47 PM, Fredrik Lundh <fredrik@pythonware.com> wrote:
C. Titus Brown wrote:
over on the pygr list, we were recently discussing a mildly confusing edit I made:
assert 'seq1' in self.db, self.db.keys() This was interpreted by someone as being
assert 'seq1' in (self.db, self.db.keys())
which is very different from the actual meaning,
assert ('seq1' in self.db), self.db.keys()
where 'self.db.keys()' serves as the message to be printed out when the assertion fails. Apart from questions of why I was apparently out to confuse people with this edit, the question of ',' precedence came up. Looking at
http://docs.python.org/ref/summary.html
there's no mention of ',' binding and tuple creation vs the other operators.
A bare "," is part of the "expression list" syntax; it's not an operator:
http://docs.python.org/ref/exprlists.html
You have to look at the statement descriptions to find out whether a statement wants an expression or an expression list (e.g. "return" takes an expression list, while "assert" takes two expressions, not two expression lists).
Note that in any case, the 'in' operator binds more tightly than the comma: e.g. f(x in y, z) means f((x in y), z). The only seeming exception to this rule is the 'for' statement (and list comprehensions and generator expressions) where 'in' is not an expression operator but part of the statement syntax. So if someone thought assert 'seq1' in self.db, self.db.keys() meant assert 'seq1' in (self.db, self.db.keys()) they'd be in for a nasty surprise trying the same trick in an 'if' statement, like this: if 'seq1' in self.db, self.db.keys(): ... Fortunately that raises a syntax error. The really bad surprises come from things like assert x in A, x in B which I've seen assumed to mean assert (x in A) and (x in B) in claimed analogy to the use of the comma in the print statement. I think in general Python has erred on the side of having too many different syntactical uses for commas. We killed a few in 3.0 with the introduction of "except E as v" and the demotion of print to a function call. Perhaps we should aim to kill "assert B, S" as well? -- --Guido van Rossum (home page: http://www.python.org/~guido/)

On Sun, Sep 14, 2008 at 3:00 PM, Guido van Rossum <guido@python.org> wrote:
I think in general Python has erred on the side of having too many different syntactical uses for commas. We killed a few in 3.0 with the introduction of "except E as v" and the demotion of print to a function call. Perhaps we should aim to kill "assert B, S" as well?
And replace it with what?
-- --Guido van Rossum (home page: http://www.python.org/~guido/) _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/musiccomposition%40gmail.c...
-- Cheers, Benjamin Peterson "There's no place like 127.0.0.1."

On Sun, Sep 14, 2008 at 1:06 PM, Benjamin Peterson <musiccomposition@gmail.com> wrote:
On Sun, Sep 14, 2008 at 3:00 PM, Guido van Rossum <guido@python.org> wrote:
I think in general Python has erred on the side of having too many different syntactical uses for commas. We killed a few in 3.0 with the introduction of "except E as v" and the demotion of print to a function call. Perhaps we should aim to kill "assert B, S" as well?
And replace it with what?
That's the question being posed. =) A quick browsing of the grammar shows us already using 'in', 'as', 'from', and 'else' as keywords that are keywords which are not statements as their own ('in' is unique, as Guido pointed out because of its use with 'for' and as an operator). Something like ``assert _expr_ else _message_`` might work, but I am not sure if people will misunderstand the meaning of 'else'. But if does somewhat match the usage with 'if' expressions as the expression following is not executed if the preceding expression is true. -Brett

And replace it with what?
I'm sure this will evolve into a long discussion on syntax, so I'll start: assert could become a function with one or two arguments. The arguments would always get evaluated; the actual exception-raising could still be conditional (perhaps through a context manager). Regards, Martin

Martin v. Löwis wrote:
And replace it with what?
I'm sure this will evolve into a long discussion on syntax, so I'll start: assert could become a function with one or two arguments. The arguments would always get evaluated; the actual exception-raising could still be conditional (perhaps through a context manager).
+1 for a function +0.5 for the else suggestion Michael
Regards, Martin _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/fuzzyman%40voidspace.org.u...
-- http://www.ironpythoninaction.com/ http://www.voidspace.org.uk/ http://www.trypython.org/ http://www.ironpython.info/ http://www.theotherdelia.co.uk/ http://www.resolverhacks.net/

On Sun, Sep 14, 2008 at 10:45:39PM +0200, "Martin v. L?wis" wrote: -> > And replace it with what? -> -> I'm sure this will evolve into a long discussion on syntax, so -> I'll start: assert could become a function with one or two -> arguments. The arguments would always get evaluated; the actual -> exception-raising could still be conditional (perhaps through -> a context manager). Doesn't this change the behavior in optimized code, for assert statements with side effects? If we don't have specialized syntax -- that is, if 'assert' just becomes another built-in function -- then it can't be special-cased in the translation to byte-code, can it? --titus -- C. Titus Brown, ctb@msu.edu

Doesn't this change the behavior in optimized code, for assert statements with side effects?
That's why I said it will be a long discussion :-) I would also propose the elimination of the -O option, and the notion of optimized code. People who want to save the time for execution of the assert statements could use some kind of source transformation, which might be easy to implement with lib2to3 (or a generalization thereof).
If we don't have specialized syntax -- that is, if 'assert' just becomes another built-in function -- then it can't be special-cased in the translation to byte-code, can it?
It still could. First, assert may continue to be a statement, even though it is invoked as a function call, similar to None, True, False. In that case, the compiler could still eliminate it, or (IMO preferred), wrap it into a conditional statement that checks whether assertions are disabled, and, if so, jumps over the assertion. Even if it isn't a keyword, the compiler could still special-case it, and add a run-time check to determine whether assert is still bound to the built-in assert. Regards, Martin

On Sun, Sep 14, 2008 at 10:59:23PM +0200, "Martin v. L?wis" wrote: -> > Doesn't this change the behavior in optimized code, for assert -> > statements with side effects? -> -> That's why I said it will be a long discussion :-) -> -> I would also propose the elimination of the -O option, and the notion -> of optimized code. People who want to save the time for execution of the -> assert statements could use some kind of source transformation, which -> might be easy to implement with lib2to3 (or a generalization thereof). I would very much like this. I think it solves some problems in the unittest-refactoring area, too, where we have a proliferation of 'assert*' functions that *don't* get removed by optimization. (Hey, does anyone want to discuss what color THAT bikeshed roof should be some more? ;) In any case, I would still like to be able to test my optimized code by using assert, which isn't possible currently. cheers, --titus -- C. Titus Brown, ctb@msu.edu

Martin v. Löwis wrote:
Even if it isn't a keyword, the compiler could still special-case it, and add a run-time check to determine whether assert is still bound to the built-in assert.
Then we would have something that looks exactly like an ordinary function call but actually isn't. I'm not sure that's a good idea. Also there are issues such as what happens if you shadow it. -- Greg

I like Martin's proposals (use a function, remove -O) very much. Actually I wanted to propose the same months ago. Here is my take at the assert function, which I would like to be able to raise even exceptions different from AssertionError: def assert_(cond, exc, *args): """Raise an exception if cond is not satisfied. exc can be a template string (then args are the interpolation arguments) or an exception class (then args are passed to the constructor). Here are a few examples: >>> assert_(False, 'ahia!') Traceback (most recent call last): ... AssertionError: ahia! >>> assert_(False, ValueError) Traceback (most recent call last): ... ValueError >>> a = 1 >>> assert_(isinstance(a, str), TypeError, '%r is not a string' % a) Traceback (most recent call last): TypeError: 1 is not a string """ if isinstance(exc, basestring): raise AssertionError(exc % args) elif inspect.isclass(exc) and issubclass(exc, Exception): raise exc(*args) else: raise TypeError('The second argument of assert_ must be a string ' 'or an exception class, not %r' % exc) M. Simionato

On Mon, Sep 29, 2008 at 7:12 AM, Michele Simionato <michele.simionato@gmail.com> wrote:
I like Martin's proposals (use a function, remove -O) very much.
That's too bad, since I don't like it at all :-). You can write your own function trivially that does this; however IMO the *language* should support something that can be disabled to the point where no code is generated for it. Most languages have this (in fact Java *added* it). I'll concede that -O is not necessary the right flag to pass, but I do want to be able to write asserts that can be turned into nothing completely, and unless we were to add macros for just this purpose, it'll have to be something recognized by the compiler, like a statement. Most other details are negotiable (like the exact syntax, or the flag used to disable it). However I don't like changing the syntax so that it resembles a function call -- that's not going to resolve the existing confusion and will add more confusion ("why can't I write my own assert() function?"). -- --Guido van Rossum (home page: http://www.python.org/~guido/)

On Sun, Sep 14, 2008 at 1:06 PM, Benjamin Peterson <musiccomposition@gmail.com> wrote:
On Sun, Sep 14, 2008 at 3:00 PM, Guido van Rossum <guido@python.org> wrote:
I think in general Python has erred on the side of having too many different syntactical uses for commas. We killed a few in 3.0 with the introduction of "except E as v" and the demotion of print to a function call. Perhaps we should aim to kill "assert B, S" as well?
And replace it with what?
I have no idea. Use your imagination. :-) -- --Guido van Rossum (home page: http://www.python.org/~guido/)

Greg Ewing wrote:
Guido van Rossum wrote:
Perhaps we should aim to kill "assert B, S" as well?
Maybe
assert B else S
?
If we really want to change it, I think: assert B as S is better because S is the string to report; that is, "if B is false, report the problem as the string S". 'else' implies to me what to do if you're not failing the assert, which is not the case. Personally I'm not convinced the syntax is so unusual as it currently stands.

On Sun, Sep 14, 2008 at 11:36 PM, Eric Smith <eric@trueblade.com> wrote:
If we really want to change it, I think: assert B as S is better because S is the string to report; that is, "if B is false, report the problem as the string S".
'else' implies to me what to do if you're not failing the assert, which is not the case.
Doesn't imply that to me. I read it as 'first you assert that B is true; if not (else), you print S'. Personally, I like 'else' better than 'as', because 'as' seems to contain the notion of assignment. -- Cheers, Leif

On Sun, Sep 14, 2008 at 8:55 PM, Leif Walsh <leif.walsh@gmail.com> wrote:
On Sun, Sep 14, 2008 at 11:36 PM, Eric Smith <eric@trueblade.com> wrote:
If we really want to change it, I think: assert B as S is better because S is the string to report; that is, "if B is false, report the problem as the string S".
'else' implies to me what to do if you're not failing the assert, which is not the case.
Doesn't imply that to me. I read it as 'first you assert that B is true; if not (else), you print S'.
Personally, I like 'else' better than 'as', because 'as' seems to contain the notion of assignment.
That's my gut feeling too, but I don't like 'else' all that much either (if would also make things like"assert x if t else b, msg" less readable I think). Maybe "assert B with S"??? FWIW I don't like turning it into a function either, and I *really* don't like keeping the keyword but changing the syntax to be function-like. -- --Guido van Rossum (home page: http://www.python.org/~guido/)

on 15.09.2008 06:12 Guido van Rossum said the following:
On Sun, Sep 14, 2008 at 8:55 PM, Leif Walsh <leif.walsh@gmail.com> wrote:
On Sun, Sep 14, 2008 at 11:36 PM, Eric Smith <eric@trueblade.com> wrote:
assert B as S
Personally, I like 'else' better than 'as', because 'as' seems to contain the notion of assignment.
That's my gut feeling too, but I don't like 'else' all that much either (if would also make things like"assert x if t else b, msg" less readable I think). Maybe "assert B with S"???
FWIW I don't like turning it into a function either, and I *really* don't like keeping the keyword but changing the syntax to be function-like.
FWIW, Java's assert syntax is:: assert Expression1 : Expression2 ; which I regularly tried to write in Python when I started with it... (minus the semicolon of course)

What I really want is for the need to be less common. What if assert recognized certain commonly used expression types and actually generated appropriate error messages?
assert foo.answer == 42 AssertionError: expected foo.answer == 42; actual: 'a suffusion of yellow'
Maybe that's too magical. :( Failing that, I wish the message could look sort of like a comment. assert cond || message Yes, I know that symbol is used for something else in other languages... -j

On Mon, 15 Sep 2008 01:55:00 pm Leif Walsh wrote:
On Sun, Sep 14, 2008 at 11:36 PM, Eric Smith <eric@trueblade.com> wrote:
If we really want to change it, I think: assert B as S is better because S is the string to report; that is, "if B is false, report the problem as the string S".
'else' implies to me what to do if you're not failing the assert, which is not the case.
Doesn't imply that to me. I read it as 'first you assert that B is true; if not (else), you print S'.
Personally, I like 'else' better than 'as', because 'as' seems to contain the notion of assignment.
I agree with Leif on both his comments. I don't particularly see the need to change assert, but if it has to change, I'd be perfectly happy with one of "assert B else S" or "assert B except S". -- Steven

On Mon, Sep 15, 2008 at 4:49 AM, Steven D'Aprano <steve@pearwood.info> wrote:
On Mon, 15 Sep 2008 01:55:00 pm Leif Walsh wrote:
On Sun, Sep 14, 2008 at 11:36 PM, Eric Smith <eric@trueblade.com> wrote:
If we really want to change it, I think: assert B as S is better because S is the string to report; that is, "if B is false, report the problem as the string S".
'else' implies to me what to do if you're not failing the assert, which is not the case.
Doesn't imply that to me. I read it as 'first you assert that B is true; if not (else), you print S'.
Personally, I like 'else' better than 'as', because 'as' seems to contain the notion of assignment.
I agree with Leif on both his comments. I don't particularly see the need to change assert, but if it has to change, I'd be perfectly happy with one of "assert B else S" or "assert B except S".
In private mail someone suggested the Java assert syntax: assert expression : expression -- --Guido van Rossum (home page: http://www.python.org/~guido/)

Guido van Rossum wrote:
In private mail someone suggested the Java assert syntax:
assert expression : expression
and in 2015, we'll get a message from you where you say: "I think in general Python has erred on the side of having too many different syntactical uses for colons." (yes, I've checked. you shouldn't leave the time machine connected to the net when you're not there.) </F>

Greg Ewing wrote:
'else' implies to me what to do if you're not failing the assert, which is not the case.
Strange, because I see it exactly the opposite way: it's saying "assert that B is true, but if not, report this error message."
Strange, because this whole thing is saying "AppleScript" to me. </F>

C. Titus Brown wrote:
Hi folks,
over on the pygr list, we were recently discussing a mildly confusing edit I made:
assert 'seq1' in self.db, self.db.keys()
For those suggesting changing the syntax of the assert statement due to this misinterpretation, what makes this any more ambiguous than doing the same thing in a function call or tuple literal?
'1' in '123', 2 (True, 2) 1 and 2, lambda: 1, 3 or 4 (2, <function <lambda> at 0xb7704a3c>, 3)
x = '1' in '123', 2 x (True, 2) x = 1 and 2, lambda: 1, 3 or 4 x (2, <function <lambda> at 0xb770410c>, 3)
def f(*args): print args ... f('1' in '123', 2) (True, 2) f(1 and 2, lambda: 1, 3 or 4) (2, <function <lambda> at 0xb770410c>, 3)
Defining ',' as an "operator" in the predecence table may be technically incorrect (since there is no actual comma operator), but giving it an entry indicating that it has even lower precedence than lambda would make it clear how the above expressions are meant to be parsed (and when parentheses are going to be needed to force the correct interpretation). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- http://www.boredomandlaziness.org
participants (16)
-
"Martin v. Löwis"
-
Benjamin Peterson
-
Brett Cannon
-
C. Titus Brown
-
Eric Smith
-
Fredrik Lundh
-
Greg Ewing
-
Guido van Rossum
-
Jason Orendorff
-
Leif Walsh
-
Michael Foord
-
Michele Simionato
-
Nick Coghlan
-
skip@pobox.com
-
Stefan Rank
-
Steven D'Aprano