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
Python will always evaluate the arithmetic operators first (** is highest, then multiplication/division, then addition/subtraction). Next comes the relational operators. Finally, the logical operators are done last.
Parentheses have the highest precedence and can be used to force an expression to evaluate in the order you want.
Which among the following list of operators has the highest precedence? Explanation: The highest precedence is that of the exponentiation operator, that is of **.
This doesn't have anything to do with generators:
>>> a = 2
>>> "a squared is %s" % a
'a squared is 2'
>>> ("a squared is %s" % a)*a
'a squared is 2a squared is 2'
>>> "a squared is %s" % a*a
'a squared is 2a squared is 2'
>>> "a squared is %s" % (a*a)
'a squared is 4'
The %
op is performed before the multiplication, using the string and the first a
as arguments. Your a**2
works because the **
op with a
and 2
as arguments is evaluated before the %
.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With