Functions¶
Consider the expression 2 + 2
: whatever line of code it appears on, we evaluate it in its entirety before using it.
For example, x = 2 + 2
stores the result of the 2 + 2
expression, rather than the expression itself. Thus, x
now contains the value $4$.
What if we wanted to do something more complicated than a simple arithmetic equation?
Let's take as an example a simple arithmetic equation: $2x + 1$. In Math, we might want to reference this equation elsewhere by saying that we should consider $f(x)$ to be that formula. Thus, everwhere we see $f(x)$, it's actually $2x + 1$. This allows us to plug in arbitrary values and build up results:
$f(x) = 2x + 1\\\text{let }x = 4\\f(4) = 9$
We can do the same thing in programming, using "functions".
import math
len("hello")
len("")
math.sqrt(9)
math.sqrt(7)
list(range(1, 5))
list(range(8))
math.sin(0)
str(17)
import random
random.random()
Function call examples:
x = 8
y = 16
z = math.sqrt(16)
u = math.sqrt(y)
v = math.sqrt(8 + 8)
w = math.sqrt(x + x)
w = math.sqrt(x + x)
w
Defining a new function¶
Instead of $f(x) = 2x + 1$, we're going to define a new body of code, and give it the name dbl_plus
:
def dbl_plus(x):
return 2 * x + 1
We can then use (or "call") that code thusly:
dbl_plus(2)
x = 2 + 2
x
dbl_plus(3)
x = 346
dbl_plus(x)
Practice Reading¶
def multiply(x, y):
print("x,y:", x, y)
z = 0
return x * y
x = 2
y = 1
result = multiply(3, 4)
print(result)
x = 1
z = 3.1
def multiply(x, y):
# (1) What are the values of x and y here
# the first time multiply is called?
print("x,y:", x, y)
z = 0
return x * y
x = 2
y = 1
result = multiply(3, y)
print(y) # (2) What is the value of y here?
result = multiply(x, 4)
print(result) # (3) What is the value of result here?
print(z) # (4) What is the value of z here?
More Definition Examples¶
def dbl_plus(x):
return 2 * x + 1
def instructor_name():
return "Alessia Fitz Gibbon"
def square(x):
return x * x
def calc_grade(points):
grade = points * 10
return grade
Evaluating a Function Call¶
- Evaluate the function name and its parameters
x = 3
y = 4
x * y
3 * y
3 * 4
12
12
def square(n):
return n ** 2
square
<function __main__.square(n)>
x = 3
y = 4
z = square(x * y)
square
evaluated to ensure it is a function (that the open parentheses(
is going to be syntactically correct).- The
x * y
expression and sub-expressions are evaluated.x
becomes3
,y
becomes4
, then the wholex * y
becomes12
.
# As such, we're essentially calling:
z = square(3 * 4)
z = square(12)
- Python creates a new frame dedicated to this function.
- Aside: a "frame" is a container internal to Python that contains the bindings between variables and values applicable to that scope.
- Assign the "actual parameters" (the values evaluated in step 1) to the variables named in the function's definition (the "formal" parameters)
- In this example,
3 * 4
->12
-> assigned tosquare
'sx
- In this example,
The square frame having an x set to 12 would be equivalent to doing
def square():
x = 12
...
But then we'd have no way to specify arbitrary values for square's x!
- Next, evaluate and run the entire body of the function. Every line of the function is run as normal until we reach a
return
statement.
- The
return
statement says to evaluate the given expression, and copy the value out to the original call site.
# Without functions, this would be the equivalent of:
x = 3
y = 4
x = x * y
z = x * x
- Once the
return
expression's value is copied back to the call site, we can remove thesquare
stack frame and continue with the rest of the program.