code review
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Sun Jul 1 00:17:54 EDT 2012
On Sun, 01 Jul 2012 12:20:52 +1000, Chris Angelico wrote:
> On Sun, Jul 1, 2012 at 12:06 PM, Steven D'Aprano
> <steve+comp.lang.python at pearwood.info> wrote:
>> You can't just arbitrarily stick parentheses around parts of
>> expressions and expect the result to remain unchanged. Order of
>> evaluation matters:
>>
>> 2**3**4 != (2**3)**4
>
> 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.
--
Steven
More information about the Python-list
mailing list