Alex Rivera | Logout

Python - curious/unexpected behaviour - precedence of operators

Asked 2012-08-07T14:10:12.013
8

I have recently been experimenting with python generators a bit, and I came across the following curious behaviour, and I am curious to understand why this happens and what is going on:

def generating_test(n): 
    for a in range(n): 
        yield "a squared is %s" % a*a # Notice instead of a**2 we have written a*a

for asquare in generating_test(3): 
    print asquare 

Output:

a squared is 1
a squared is 2a squared is 2

Versus the following script which generates the expected output:

def generating_test(n): 
    for a in range(n): 
        yield "a squared is %s" % a**2 # we use the correct a**2 here

for asquare in generating_test(3): 
    print asquare 

Output:

a squared is 0
a squared is 1
a squared is 4
Edit
Report

2 Answers

8

Python's order of operations is from left-to-right except where PEMDAS applies. The string interpolation operator apparently has the same precedence as modulo and multiplication, because if you reverse the order, making the multiplication left of the interpolation, it takes precedence:

>>> print 3 * "a foo %s" % 'hi'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: not enough arguments for format string
>>> print 3 * "a foo %s" % ('hi', 'ho', 'yo')
a foo hia foo hoa foo yo

However, as you've demonstrated, exponentiation trumps left-to-right order.

Update: In that same document under Binary Arithmetic Operations it states something denotatively obvious, but connotatively relevant:

…the % operator is also overloaded by string and unicode objects to perform string formatting (also known as interpolation).

While that appears to just be telling you what the % operator does, I think its location and context also tells you it has the same precedence whether it's used as modulo or interpolate.

answered 2012-08-07T14:21:29.633
5

When you observe unexpected behaviour, start your analysis by distilling it to its simplest possible case. A simple case will easier to study and comprehend.

The unexpected behaviour:

>>> 'hello %s' % 3 * 2
'hello 3hello 3'

(You expected 'hello 6')


We reason Python must be interpreting the command as 'hello 3' * 2 rather than 'hello %d' % 6. We try forcing the second interpretation with brackets

>>> "hello %s" % (3*2)
'hello 6'

Eureka!

We've demonstrated that the string formatting operator % has greater or equal precedence than multiplication. We check the Python documentation - yes it confirms this http://docs.python.org/reference/expressions.html#summary

To confirm that the precedence is equal, we can try it the other way around:

>>> "%d,"*2%(1,2)
'1,2,'

Seeing that the comma (,) is duplicated, we reason that the multiplication "%d," * 2 was performed before the string formatting %. If multiplication can precede string formatting, and string formatting precede multiplication, they must be equal in precedence.

answered 2012-08-07T14:34:15.443

Your Answer