Reputation: 546
When I try this code in Python 2.7.3:
names = ["Paul", "Mary", "Susan"]
names.sort()
def valuate(string):
print ord('A')
return sum(ord(s) for s in string)
i = 1
for name in names:
print i, name, valuate(name)
i += 1
I expect the output:
65
1 Mary 409
65
2 Paul 402
65
3 Susan 522
But instead I get:
1 Mary 65
409
2 Paul 65
402
3 Susan 65
522
It seems the print
statement outputs the i
and name
values before calling the function. Is that so? Why?
Upvotes: 2
Views: 346
Reputation: 104682
The surprise you're encountering is that the print
statement prints out each of the expressions it is given before evaluating the next one. That is, a statement like print A, B, C
is equivalent to:
print A, # note, the trailing comma suppresses the newline
print B,
print C
As you'd expect from separate statements, A gets written out before B or C is evaluated.
That surprise is perhaps part of the reason that Python 3 has done away with the print
statement in favor of a builtin print
function which behaves more like you expect (all of its arguments are evaluated before the function runs).
In Python 2, you can get the Python 3 style print
if you want using a future
import:
from __future__ import print_function
Upvotes: 2
Reputation: 500157
The sequence of events is as follows:
print i,
print name,
val = valuate(name) # prints ord('A')
print val
This is confirmed by looking at the bytecodes generated for print i, name, valuate(name)
:
11 19 LOAD_FAST 0 (i)
22 PRINT_ITEM
23 LOAD_FAST 1 (name)
26 PRINT_ITEM
27 LOAD_GLOBAL 1 (valuate)
30 LOAD_FAST 1 (name)
33 CALL_FUNCTION 1
36 PRINT_ITEM
37 PRINT_NEWLINE
I don't know if this evaluation order is guaranteed (a quick search didn't reveal anything). I definitely wouldn't rely on it, and therefore wouldn't write code like this.
Upvotes: 4
Reputation: 20126
I think that a small ',' would make things a lot more simple to grasp.
names = ["Paul", "Mary", "Susan"]
names.sort()
def valuate(string):
print ord('A'),
return sum(ord(s) for s in string)
i = 1
for name in names:
print i, name, valuate(name)
i += 1
Now that outputs:
1 Mary 65 409
2 Paul 65 402
3 Susan 65 522
The comma after print
makes it not to print a new line character at the end. So now you can see that valuate
first prints the ord('A')
and then returns the output for the outer print. (I also indented the i += 1
line)
Upvotes: 0
Reputation: 13059
It's very simple. Your print statement evaluates the arguments lazily. It prints i first, then name, and then it calls valuate. Valuate prints 65. Then your print statement prints the result of valuate.
Upvotes: 3
Reputation: 5046
It's not just the print
statement, it's the function call.
print i, name, valuate(name)
Prints i
, then name
, then calls valuate
which prints 65 (and a new line) then on return the print
statement continues to print the return value (and another newline).
Upvotes: 6