Reputation: 9
When I was studying the SICP course, the execution order of the following code in the environment diagram is inconsistent with what I expected.
def add_one(x):
y = x+1
return y
def square(x):
return x*x
square(add_one(9))
I am expecting the following evaluation order:
square
. A function value is returned.add_one(9)
.add_one
. A function value is returned.9
. Now the expression add_one(9)
returns 10square(add_one(9))
return 100.However, I run the code on this website It told me that the add_one
frame created before the square
, which is opposite of what I expected. Is it right?
I asked ChatGPT about this question. It gives the answer that this is because in Python, the priority of function calls is higher than that of operators.
Upvotes: 0
Views: 74
Reputation: 11307
Your order is evaluation is mostly correct. However you are confusing "creation of the frame" with "evaluation of the frame".
To call a function, Python evaluates the function and its arguments. This order appears to be left-to-right, but I cannot find anything in the documentation that guarantees this. [Other StackOverflow answers say it is guaranteed left-to-right, so maybe there's something I'm missing.]
Only after the function and its arguments are evaluated is the function call actually made. This is when the frame is created.
Try the following code. It will give you a clearer idea of evaluation order.
def add_onex():
print("Calling add_one")
return add_one
def squarex():
print("Evaluating square")
return square
def add_one(x):
print("Calling add one")
y = x + 1
return y
def square(x):
print("Calling square")
return x * x
result = squarex()(add_onex()(9))
Obviously, in most cases, the evaluation of a function is a simple name lookup. But in cases where evaluation of the function is not trivial, you can see that this evaluation happens before the arguments are evaluated.
Upvotes: -1
Reputation: 16526
The evaluation order will be as follows:
add_one(9)
is executed, as it's the innermost nested expression10
is calculated and returned from functionsquare
function is invoked with 10
as its parameter100
is calculated and returned from function100
The big difference to your list is the order in which the functions are executed. The innermost is usually* executed first. You can think of the brackets (parentheses) that we use to invoke functions as another layer of operator priority. Things within brackets are run before things outside brackets.
While GPT is right about functions being invoked before operators, here the question is more about which function gets invoked first. Once a function is invoked, it doesn't matter what it or other functions contain - the whole function is being run using the same rules, but applied to the function body only. E.g. functions called within an expression in the function would be called before operators in the same expression.
* = the only exception being latent functions like lambdas, in which case the parameter itself is of type function. You will get to this a bit later in your studies.
Upvotes: 2
Reputation: 7059
You can't evaluate square() until you can provide it with the argument value. So add_one() has to be evaluated first so the result can be passed to square().
Upvotes: 2