5

Let's say I have

def foo(n):
    print("foo",n)

def bar(n):
    print("bar",n)

print("Hello",foo(1),bar(1))

I would expect the output to be:

Hello
foo 1 None
bar 1 None

But instead I get something which surprised me:

foo 1
bar 1
Hello None None

Why does Python call the functions first before printing the "Hello"? It seems like it would make more sense to print "Hello", then call foo(1), have it print its output, and then print "None" as it's return type. Then call bar(1) and print that output, and print "None" as it's return type. Is there a reason Python (or maybe other languages) call the functions in this way instead of executing each argument in the order they appear?

Edit: Now, my followup question is what's happening internally with Python somehow temporarily storing return values of each argument if it's evaluating the expressions left to right? For example, now I understand it will evaluate each expression left to right, but the final line says Hello None None, so is Python somehow remembering from the execution of each function that the second argument and third arguments have a return value of None? For example, when evaluating foo(), it will print foo 1 and then hit no return statement, so is it storing in memory that foo didn't return a value?

user2357112
  • 260,549
  • 28
  • 431
  • 505
rb612
  • 5,280
  • 3
  • 30
  • 68
  • 2
    The arguments are always first evaluated left to right... – Willem Van Onsem Aug 06 '17 at 22:50
  • I've pruned the dupe target list a bit. Most of the targets were talking about order of argument evaluation relative to other arguments; only one of them discussed order of argument evaluation relative to the execution of the function the arguments are passed to, which is what this question is about. – user2357112 Aug 06 '17 at 23:04
  • @user2357112 Thank you. I edited my question because there's still another part of it I'm not quite sure I understand how it works. – rb612 Aug 06 '17 at 23:05
  • @rb612 Well my question answers that. The byte code will help you understand. The intermediate values are computed, stored, and then finally passed to the function. – cs95 Aug 06 '17 at 23:07
  • 1
    Also, a function returning no values actually returns `None` by default. – cs95 Aug 06 '17 at 23:09
  • @cᴏʟᴅsᴘᴇᴇᴅ, yes that first answer is helpful. I'm curious is it storing these return statements somewhere and then recalling them to use as arguments in the print statement? – rb612 Aug 06 '17 at 23:09
  • 1
    @rb612 Yes, like I said, the intermediate values are computed and stored in temporary variables (this is an implementation detail) and then passed. – cs95 Aug 06 '17 at 23:11
  • @user2357112 I feel like this question should be reopened and others marked a duplicate of this. What say? – cs95 Aug 06 '17 at 23:14
  • @cᴏʟᴅsᴘᴇᴇᴅ: I don't think this question is a good dupe target for any of the others that were in the list. – user2357112 Aug 06 '17 at 23:19

4 Answers4

3

Quoting from the documentation:

Python evaluates expressions from left to right. Notice that while evaluating an assignment, the right-hand side is evaluated before the left-hand side.

Bold emphasis mine. So, all expressions are first evaluated and then passed to print.

Observe the byte code for the print call:

  1           0 LOAD_NAME                0 (print)
              3 LOAD_CONST               0 ('Hello')
              6 LOAD_NAME                1 (foo)
              9 LOAD_CONST               1 (1)
             12 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             15 LOAD_NAME                2 (bar)
             18 LOAD_CONST               1 (1)
             21 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             24 CALL_FUNCTION            3 (3 positional, 0 keyword pair)
             27 RETURN_VALUE

foo (LINE 12) and bar (LINE 21) are first called, followed by print (LINE 24 - 3 positional args).

As to the question of where these intermediate computed values are stored, that would be the call stack. print accesses the return values simply by poping them off of the stack. - Christian Dean

Christian Dean
  • 22,138
  • 7
  • 54
  • 87
cs95
  • 379,657
  • 97
  • 704
  • 746
  • This is great! Thank you! Just curious, is there a part in the byte code that is showing that Python is storing the return value of both `foo` and `bar`? – rb612 Aug 06 '17 at 23:10
  • 1
    @rb612 Ah. Good question. The byte code does not show this most likely since it is an implementation detail. You can see it is passed `(3 positional, 0 keyword pair)` so you know it has to be stored somewhere. – cs95 Aug 06 '17 at 23:11
  • 1
    @cᴏʟᴅsᴘᴇᴇᴅ _"so you know it has to be stored somewhere."_ - Yes. Specifically [it is stored in Python's call stack](https://github.com/python/cpython/blob/master/Python/ceval.c#L3344). In the example given, `print` access the return values simply by poping them off of the stack. – Christian Dean Aug 06 '17 at 23:25
  • @ChristianDean I know I can count on you for the implementation detail code! May I add it to my answer? – cs95 Aug 06 '17 at 23:27
  • 1
    @cᴏʟᴅsᴘᴇᴇᴅ Have at it :-) – Christian Dean Aug 06 '17 at 23:28
  • @cᴏʟᴅsᴘᴇᴇᴅ, please stop [Answering a question, then closing it as duplicate](https://meta.stackoverflow.com/questions/286072/answering-a-question-then-closing-it-as-duplicate). – randomir Aug 07 '17 at 12:06
  • @randomir it's not like I deliberately answer and close before anyone else has a chance to. It usually happens that I answer and question and someone else hints that there is a duplicate. But sure, thanks for the warning... I'll be more careful, because I understand where you're coming from. – cs95 Aug 07 '17 at 14:35
  • 1
    @randomir Sure. I appreciate you looking out for the community. – cs95 Aug 07 '17 at 14:39
3

As is specified in the documentation:

Python evaluates expressions from left to right. Notice that while evaluating an assignment, the right-hand side is evaluated before the left-hand side.

This thus means that if you write:

print("Hello",foo(1),bar(1))

It is equivalent to:

arg1 = "Hello"
arg2 = foo(1)
arg3 = bar(1)
print(arg1,arg2,arg3)

So the arguments are evaluated before the function call.

This also happens when we for instance have a tree:

def foo(*x):
    print(x)
    return x

print(foo(foo('a'),foo('b')),foo(foo('c'),foo('d')))

This prints as:

>>> print(foo(foo('a'),foo('b')),foo(foo('c'),foo('d')))
('a',)
('b',)
(('a',), ('b',))
('c',)
('d',)
(('c',), ('d',))
(('a',), ('b',)) (('c',), ('d',))

Since Python thus evaluates arguments left-to-right. It will first evaluate foo(foo('a'),foo('b')), but in order to evaluate foo(foo('a'),foo('b')), it first needs to evaluate foo('a'), followed by foo('b'). Then it can all foo(foo('a'),foo('b')) with the results of the previous calls.

Then it wants to evaluate the second argument foo(foo('c'),foo('d')). But in order to do this, it thus first evaluates foo('c') and foo('d'). Next it can evaluate foo(foo('c'),foo('d')), and then finally it can evaluate the final expression: print(foo(foo('a'),foo('b')),foo(foo('c'),foo('d'))).

So the evaluation is equivalent to:

arg11 = foo('a')
arg12 = foo('b')
arg1 = foo(arg11,arg12)
arg21 = foo('c')
arg22 = foo('d')
arg2 = foo(arg11,arg12)
print(arg1,arg2)
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
2

The enclosing function is not called until all of its arguments have been evaluated. This is consistent with the basic rules of mathematics that state that operations within parentheses are performed before those outside. As such print() will always happen after both foo() and bar().

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • This makes sense, so is the return value of `None` just stored somewhere for `foo` and `bar` until the `print` statement is called? It seems like it would make sense for `None` to appear immediately following the execution of `foo` and `bar` respectively. – rb612 Aug 06 '17 at 22:57
  • 1
    Operations within parentheses aren't always performed before those outside, in math or in Python. While it's common to teach precedence as "order of operations" in early math classes, even in math, it's just an argument grouping convention. – user2357112 Aug 06 '17 at 23:00
  • @rb612: Nothing can "appear", since `print()` hasn't even been invoked yet. – Ignacio Vazquez-Abrams Aug 07 '17 at 00:04
1

The answer is simple: In python the arguments of a function like print are always first evaluated left to right.

Take a look at this stackoverflow question: In which order is an if statement evaluated in Python

And None is just the return value of the function. It executes the function first and then print its return value

Liam
  • 6,009
  • 4
  • 39
  • 53