But that's because ** binds right to left. It _is_ valid to say:
2**3**4 = 2**(3**4)
Yes, but my point is that you can't just add parentheses arbitrarily
without understanding what you're doing.
If you're used to some feeble $2 calculator that doesn't implement
operator precedence, you might expect that you could do this too:
1+2*3
(1+2)*3
But you can't. It's your expectations that are skewed, not Python.
If you (generic you) are used to some feeble $2 language that doesn't
implement chained comparisons, it is your expectations that are skewed,
not Python.
Comparisons were invented long before C, or even computers, and they have
had chained semantics long before Python. Languages like C force you to
unlearn the standard semantics of comparisons, and substitute something
that is less expressive, less powerful, less efficient, and more likely
to contain a bug.
This is almost always wrong in languages without chained comparisons:
a < func(x) < b
This is inefficient, and still wrong, if x has side-effects or isn't
reentrant:
a < func(x) and func(x) < b
This is too verbose for such a simple comparison:
tmp = func(x)
(a < tmp) and (tmp < b)
[...]
Everyone who knows algebra knows that the parens are optional, but
nobody would expect them to change the evaluation of the expression.
Nonsense. Of course parens change the evaluation of the expression.
That's what parens are for!
There may be some specific cases where they don't, because you have
happened to put them in a specially crafted position where they don't
actually change the order of evaluation. E.g. putting parens around the
entire expression, or putting them around a single atom, or around
another pair of parentheses:
2*(3+4)
=> (2*(3+4)) # unchanged
=> (2)*(3+4)
=> 2*((3+4))
but just because there are *some* places you can add redundant parens
doesn't mean that you can add them *anywhere*. You have to understand the
semantics of expression, including the precedence rules. If you don't
understand them, you might as well be just adding parens in random
positions, in which case you should expect the semantics to change.
[...]
(a<b)<=(c<d)
is, incidentally, a valid expression, as long as you accept that False
is less than True.
Right. I'm not saying that there's never any need to evaluate a
comparison, and then compare it to the result of another comparison.
That's a perfectly valid thing to do.
And you know what? You can do it, using parens, exactly as shown.
Chained comparisons is the common case, it should have the simple syntax.
That's why mathematicians write {x : a < x < b} instead of
{x: a < x} ∩ {x: x < b}. The uncommon case, treating a bool as a value to
be compared to another value, should be possible, which it is.