[Tutor] revisiting a puzzle about -3**2 vs (-3)**2

Steven D'Aprano steve at pearwood.info
Thu Aug 13 03:31:26 CEST 2015


On Wed, Aug 12, 2015 at 12:14:16PM -0700, D Wyatt wrote:
> >
> >>>> pow(-3, 2)
> > 9
> >
> > I'm explicitly telling Python I want the value -3 raised
> > to the power 2.
> >
> >
> > Alan G
> 
> so passing any numeric expression in a function is like putting ()
> around it, correct?

Hmmm. I suppose that in a manner of speaking the answer is Yes, but I 
don't think that's a helpful way of looking at things. Or at least not 
accurate.

Parentheses (round brackets) are used for various tasks in Python, 
including calling functions and for grouping. (There are also others.)

When you say 

    pow(-3, 2)

the brackets () mean "call this function". The contents of the brackets 
are treated as the arguments. In this case, the parsing rules used by 
the Python interpreter treat the - sign as stronger than than comma, so 
that it applies - to the 3. It has nothing to do with the brackets. One 
might do this as well, with no brackets involved:

my_tuple = -3, 2

which gives a tuple of two values, minus-three and two, and NOT a tuple 
of (3, 2) which then has the - operator applied to it. (That would cause 
an error.)

When the parser splits apart each line of code to analyse it in 
preparation for executing it, it has to decide in which order each 
operation applies. Often that's just left-to-right, but operators can 
change that, since we want mathematical expressions to match the rules 
learned in maths class, not just left-to-right evaluation.

So each operator has a priority. The higher the priority, the earlier it 
applies. If you dislike that precedence, the way to tell the interpreter 
to use your own priorities is to group the terms in brackets first, just 
like in maths class.

Multiplication has higher priority than addition, so:

    1+2*3 == 7 

not 9. If you want to do the addition first, you can write:

    (1+2)*3 == 9

Exponentials have higher priority still:

    2*3**2 == 18 

and not 36, again just like maths class. The unary + and - operators 
have quite low priority, but commas are even lower. (Technically, the 
comma isn't actually considered an operator, but the difference is 
subtle and doesn't really matter for this discussion.)

So the differences in behaviour between:

    -3**2

    (-3)**2

    pow(-3, 2)

etc are all to do with the order of operations, not specifically the 
parens. It just happens that parentheses can be used to change the order 
of operations. Let's go through each it turn:

-3**2: since exponentiation ** has highest priority, that calculates as 
3**2 gives 9, then apply the - sign to get -9.

(-3)**2: since brackets *used for grouping* are highest priority, that 
calculates as 3, apply the - sign to get -3, raise to the power of 2 to 
get 9.

pow(-3, 2): the brackets here are used for a function call, not 
grouping. The parser effectively looks inside the brackets and splits on 
commas, giving two expressions: "-3" and "2". The "-3" expression is 
treated as 3, apply the minus sign to get -3, and the "2" expression is 
obviously just 2.

So pow() receives two arguments, -3 and 2 exactly as you would 
expect, and calculates -3 squared which is 9.

To check your understanding, can you predict what this will do?


x = 2
y = -2
print(x**3, y**3, -x**3, -y**3)


(Note that this time I am using cubes, not squares.)


-- 
Steve


More information about the Tutor mailing list