Lecture Notes 22: More About Functions
Review of Execution Flow
Possible lingering confusion about execution flow:
- where can the functions be defined?
- order of execution when there is function composition
- Where can variables be used?
Standalone or Module code
We've seen how to use functions defined inside our programs:
def factorial ( a ):
# iterative approach
mult = 1
for i in range (1,a+1):
mult*=i
return mult
def summation ( a ):
# iterative approach
summat = 0
for i in range (a+1):
summat+=i
return summat
def main ():
num = 12
fac = factorial(num)
summ = summation(num)
print(f"the factorial of {num} is {fac};\n" \
f"the summation of {num} is {summ}" )
main()
Activity 1 [2 minutes]:
- Open a scratchpad project in Replit (if you don;t aready have one)
- Create a new file called my_operations.py
- copy the code shown above inside my_operations.py
- Open the tab (on the right pane) called Shell
- Run your file using the instruction: python3 my_operations.py
you should get the following output:
the factiorial of 12 is 479001600;
the summation of 12 is 78
As you can you imagine, these two operations might be useful in other contexts... and it would be wasteful to have to write them all over again, soooo....
What if we wanted to make use of this code from another program?
Imagine we want to
import!
Say we do something like this:
import my_operations
def main ():
num = 7
fac = my_operations.factorial(num)
summ = my_operations.summation(num)
print(f"the factorial of {num} is {fac};\n" \
f"the summation of {num} is {summ}" )
main()
What could go wrong?
Activity 2 [2 minutes]:
- In the scratchpad project
- open the file called main.py
- copy the code shown below inside main.py
- Run your file using the green Run button (or in the shell with the instruction: python3 main.py)
What is ...
unexpected?
We've discussed the concept of
importing code so it can be used in other programs.
However, we have not seen how python avoids executing the imported program's
main function (which it might as well have)!
The __name__ environment variable
When a program is executed, it is done so inside an execution context that, besides keeping track of the program's variables and code, has what are called
environment variables.
One such invironment variable is called
__name__ variable.
When a program is rune, the
__name__ variable has one of two values:
- it contains string "__main__" if the progra executed as a standalone program
- it contains the name of the script if the progra was imported
Activity 3 [2 minutes]:
- In the scratchpad project
- Modify the file called my_operations.py as shown below:
def factorial ( a ):
# iterative approach
mult = 1
for i in range (1,a+1):
mult*=i
return mult
def summation ( a ):
# iterative approach
summat = 0
for i in range (a+1):
summat+=i
return summat
def main ():
num = 12
fac = factorial(num)
summ = summation(num)
print(f"the factorial of {num} is {fac};\n" \
f"the summation of {num} is {summ}" )
if __name__ == "__main__":
main()
- Open the tab (on the right pane) called Shell
- Run your file using the instruction: python3 my_operations.py
You should get the SAME result as before!
- However.... Now run the code in main (Green Run button)
What ...
changed?
What is happening is this:
- when the program my_operations.py is run directly (standalone) the __name__ for it is "__main__" so the if statement triggers and the main is initiated.
- However, when it gets imported, the __name__ for it is "my_operations.py" so the if statement is not triggered and its main is not executed
- Now, the main inside the program called main.py can make use of the functions inside the module my_operations.py as usual.
For completeness sake, we should actually write the main inside
main.py like this:
import my_operations
def main ():
num = 7
fac = my_operations.factorial(num)
summ = my_operations.summation(num)
print(f"the factorial of {num} is {fac};\n" \
f"the summation of {num} is {summ}" )
if __name__ == "__main__":
main()
Multiple parameters and default values
Functions can be defined to take in multiple parameters:
def emphasize(word, my_char):
print(my_char.join(list(word)))
emphasize("Monday", "-")
Here the output would be:
M-o-n-d-a-y
We can include a “default” value for some (or all) of them:
def emphasize(word, my_char = "*"):
print(my_char.join(list(word)))
emphasize("Monday")
Here the output would be:
M*o*n*d*a*y
In this case we can call emphasize with only one parameter.
Activity 4 [2 minutes]:
- open the the scratchpad project
- In the my_operations.py file, add the function (shown bellow) called partial_sum that
takes two input arguments, x, and y, and returns the partial sum from the smaller to the larger of the two.
def partial_sum ( x , y):
small = 0
big = 0
if x < y:
small = x
big = y
else:
small = y
big = x
summat = 0
for i in range (small, big+1):
summat+=i
return summat
-
Now modify this program with default values so that the defaults are:
- if only one value is sent, the result is the sum from 0 to the number
- if no values are sent, the result is 0
Function Composition (Chaining)
Return values allow us to call functions inside other function calls:
>>> n = int(input("Enter an integer: "))
>>> n = int("3")
Similarly,
boom = emphasize(input("Enter a word: ")
Readability and Comments
- spacing
- parentheses
- Comments
Example:
fahrenheit = 212
celsius = (fahrenheit - 32) * 5 / 9
Fahrenheit to Celsius.
# calculate the area of a triangle
base = 20
height = 12
area = base * height / 2
Scope
Scope refers to the "area of influence" of a variable or name.
It is the block of code in which it is "alive" and where it could be used.
Look at a modified version of the final code used above:
def factorial ( a ):
# iterative approach
mult = 1
for i in range (1,a+1):
mult*=i
return mult
def summation ( b ):
# iterative approach
summat = 0
for i in range (b+1):
summat+=i
return summat
def main ():
num = 4
fac = factorial(num)
summ = summation(num)
print(f"the factorial of {num} is {fac};\n" \
f"the summation of {num} is {summ}" )
if __name__ == "__main__":
main()
If you notice the code for our example,
a exists for a brief period of time (only while at factorial).
It's "alive" from the moment the function
factorial is invoked and the
argument (\(12\)) is inserted into the function
parameter a.
We say that the variable
a is
bound to 12.
Lastly,
a is no longer saved after the function returns.
Try it in the
Python Tutor
Let's see another example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | # This is the Definition Section
def addThree(x):
print ('the input was: ' + str(x) ) # concatenation
y = 0 # not necessary
y = x + 3
print ('I will return:', y) # comma notation
return y
# This is the Action Section
x = 7
print ('The value of x before \'addThree\' is:', x)
x = addThree(x)
print ('The value of x after \'addThree\' is:', x)
# Was it the value you expected?
# Could I print y here?
|
Answer the following questions before you try it out in the Python Tutor:
Activity 5 [2 minutes]:
- What value of x will be printed at the end?
- What is happening with x when we invoke addThree(x)?
- What is happening with x after we invoke addThree(x)?
- What is happening with x when we return from addThree(x)?
- Can we print y at the end?
Try it out in the
Python Tutor
The Global Scope
As you can see from where some variables are visualized in the Python Tutor, there is something called
The Global Scope!
The global scope corresponds to the maximum scope of the python program (the most external one).
creating variabls at this level let's
any other part of the program interact with it.
Global variables are frowned upon because of this.
Some reasons for this is that one might have unexpected side effects from functions using a
global variable.
if you see the
global keyword used inside a function, that is telling Python to look for the variable in the global scope.
This opens up the chance for that function to modify the variable.
ZyBooks mentions and uses them, but we'll try to avoid using them as we learn more about functions and scope.
The general rule is:
A variable's scope is that of the innermost function, class or module in which they're assigned.
We will see more details about
scope when we see
Conditionals (next class).
Arguments, Parameters, and Local Variables
As you saw above, we have several values being saved into variables and use differently depending on their scope.
First, a couple definitions:
Arguments
In the code shown above,
x is present both as an
argument (value or variable passed to a function) of the function
addThree,
and as the
Left-Hand-Side variable in the assignment.
The order of execution is:
- First resolve the value of x
- then copy that value into the parameter used inside the function
- Once the function returns, assign the return value to the Left-Hand-Side variable of the assignment.
Parameters
In the function definition for
addThree, we have:
Which has a single
parameter that will be received as input.
Activity 6 [2 minutes]:
Answer the following questions:
- What is this parameter's Scope?
- Does it matter how we name this variable as long as it is a valid identifier? (try it)
Local Variables
Once a function has been
invoked with arguments, the values of the arguments are copied into the appropriate parameters and used inside the function as
local variables (with the scope local to the function only).
You can also declaree additional variables inside the function and use them while inside the function.
Activity 7 [2 minutes]:
What is an example of a local variable inside addThree?
Function Composition
Function calls can be used as the argument of another function.
This might sound odd and complicated, but it is just like a pipeline of transformations that we link up.
We've also been doing it for a while:
print('The next number is: ' + str( 1 + int( input('number?') ) ) )
Activity 8 [2 minutes]:
What is the output?
Try
it out
Another example:
# Definition Section
def times3 (num):
return num*3
def minus1 (num):
return num - 1
# Action section
x = input ('gimme a num: ')
x = int(x) # this redefines x
y = minus1( times3(x) )
print('the output of 3x+1 is:',y)
Answer the following questions before trying it out:
Activity 9 [2 minutes]:
- Which function is called first?
- Where does the return value of the first function go?
Try
it out
Homework
[Due for everyone]
TBD
[Optional] TODO