You are on page 1of 61

EECS 1015

Introduction to Computer Science and Programming

Topic 5
Functions and Modules

Fall 2021
Michael S. Brown
EECS Department
York University

EECS1015 – York University -- Prof. Michael S. Brown 1


Functions so far
• In previous lectures, we have been using built-in Python functions
• Some examples:
int("string") returns an integer
float("string") returns a float
str(20) returns a string
str(20.9) returns a float
input("string") returns a string
print("string") returns (nothing)
randint(1,100) returns a random number from between 1 and 100

What do they have in common?


(1) They perform some action.
(2) All are "passed" some data to be processed.
(3) Most return some value (the only one that didn't was print)

EECS1015 – York University -- Prof. Michael S. Brown 2


Modules
• Modules represent a group of functions

• We have seen one example of a module:


The random module
import random
random.randint(1,100)

randint() the function we use.


There are many more functions.
These functions all
seed()
are part of the
randrange()
random module
random()
….

EECS1015 – York University -- Prof. Michael S. Brown 3


In this lecture
• We will see how to define our own functions and organize them
into modules.

• Why do we need functions?


• Functions help break our program into smaller and modular chunks. As our
program grows larger and larger, functions make it more organized and
manageable.

• Furthermore, it avoids repetition and makes the code reusable.

EECS1015 – York University -- Prof. Michael S. Brown 4


Goal of this lecture
• To learn how to define and use functions

• To understand the different ways data can be passed to functions

• To understand variable scoping, in particular local and global scope

• To understand modules and the "special variable" __name__

• To continue thinking like the Python interpreter

EECS1015 – York University -- Prof. Michael S. Brown 5


Part 1: Defining and calling functions,
and the "Call Stack"

EECS1015 – York University -- Prof. Michael S. Brown 6


What is a function?
• A function is a group of related statements that performs a specific
task.
• We can think of a function as a "mini-program"

• You can pass data to a function that can be used by the function's
statements

• The function can also return data back

EECS1015 – York University -- Prof. Michael S. Brown 7


Function syntax
Parameters that can be given to the
Function name
Keyword def, short for "define" function (optional – you don’t' have to have
parameters)
String that explains def function_name(param1, param2, …[optional]): colon
how your function """docstring"""
works. statement
statement
Notice all statements
return data1, data2, … (optional)
in the function body
Optional return of data.
are indented to the same
(you don’t have to return
level, just like if, while, and for.
Example data)
def strEqual(str1, str2):
"""Checks if two strings are equal by ignoring case.
The func returns a Boolean"""
str1Upper = str1.upper()
str2Upper = str2.upper()
result = (str1Upper == str2Upper)
return result
EECS1015 – York University -- Prof. Michael S. Brown 8
"Calling" a function
def strEqual(str1, str2):
"""Checks if two strings are equal by ignoring case. Function is defined here.
The func returns a Boolean""" The code for this function
str1Upper = str1.upper() only executes when the
str2Upper = str2.upper() function is "called"
result = (str1Upper == str2Upper)
return result

a = "hello"
b = "HELLO"
if strEqual(a, b): Example of calling the
print("Strings are equal.") function. Since the function
else:
print("Strings aren't equal.")
returns a Boolean, we can
use it in an if-statement.

Strings are equal.

https://trinket.io/python/5b69ae38f3
EECS1015 – York University -- Prof. Michael S. Brown 9
Function "call signature"
def function_name(name, age, weight, height):
"""docstring"""
statement
The parameter list is also known as the
statement
function's call signature. This tells Python how
return data1 many arguments need to be passed to the function.
Example
def computeBMI(weight, height):
BMI = (height*height) / weight
return BMI This call does not use the
correct call signature. There should be
bmi = computeBMI(72, 180) two parameters. This will cause
bmi = computeBMI(72) an TypeError.

bmi = computeBMI(72)
Program output TypeError: computeBMI() missing 1 required positional
argument: 'height'
EECS1015 – York University -- Prof. Michael S. Brown 10
Calling the function - TypeError
• If your function call does not match the function's call signature, you
will get a "TypeError."

• It might seem strange that this is a TypeError, but you can think that
your function is an object of type "function" whose type also includes
the call signature.

• If your call doesn't match the call signature, then your call is the
wrong Type.

EECS1015 – York University -- Prof. Michael S. Brown 11


Passing data to a function
def strEqual( str1, str2):
Inside the function, the parameters str1 and str2
"""…"""
str1Upper = str1.upper() are used to access the data "passed" to the function
str2Upper = str2.upper() by a call.
result = (str1Upper == str2Upper)
return result

a = "hello"
b = "HELLO"
The strings bound to a and b
if strEqual(a, b):
print("Strings are equal.") are passed into the function call strEqual(a,b).
else:
print("Strings aren't equal.")
The function can be called as many times as we
c= "HeLo" want. We can pass different data each time we make
if strEqual(a, c): a call. For this call, we pass the data bound to a and
print("Strings are equal.") c – strEqual(a,c).
else:
print("Strings aren't equal.") This shows how functions can be "reused" over and
over.
https://trinket.io/python/a4e210fa90
EECS1015 – York University -- Prof. Michael S. Brown 12
Parameter and arguments
Calling the function (arguments) Function definition (parameters)
num = int(input("Input number: ")) def processNum( x )
result = processNum(num)
print(result) # compute some number
print(processNum(5)) y = x**2 + 5*x – 2
The parameter is what is declared
return y in the function. The parameter
here is x.

The argument is what is passed to the


function. Here the function is called twice.
The first call, the argument is whatever
num is bound to.
The second call, the argument is the
integer literal 5.

Note: When "googling" you may also see this referred to


as follows: parameter is called the "formal argument"
and the argument is called the "actual argument". In
EECS1015 – York University -- Prof. Michael S. Brown EECS1015, we will use the parameter/argument terminology.
13
Think like an interpreter (1/5)
Let's consider how the interpreter When the interpreter starts, it scans the python file.
treats function definitions and function calls. It see that there is a function defined and treats this
like an object and creates an entry in memory.
0: def processNum( x ): It also knows that the function has a parameter with the name "x"
1: y = x**2 + 5*x – 2
2: return y based on the function's call signature.

3: num = input("Input number: ") List of variables Data/Objects stored in memory


4: num = int(num) processNum(param: x) (function)
5: result = processNum(num) num
6: print(result) result
Based on the function's call signature,
Python knows this takes 1 parameter.

So, before the program runs, the interpreter has the


information above.

EECS1015 – York University -- Prof. Michael S. Brown 14


Think like an interpreter (2/5)
Examine program step by step. So, before the program begins, we have this information.
0: def processNum( x )
1: y = x**2 + 5*x – 2 Data/Objects stored in memory
2: return y processNum(param: x) (function)
3: num
4: num = input("Input number: ") result
5: num = int(num)
6: result = processNum(num)
7: print(result)
IMPORTANT: Where will the program start?
Your program will not perform the code in a function until it is
called. So, in this code, the program will start at the line 4,
since this is the first line of code that isn't a function.

Lines: 4 & 5. Inputs data, converts to integer and binds it.


0: def processNum( x )
1: y = x**2 + 5*x – 2 Let's assume the user provided "5" as input.
2: return y
List of variables Data/Objects stored in memory
3:
4: num = input("Input number: ")
num processNum(param: x) (function)
5: num = int(num) 5 (integer)
6: result = processNum(num) result
7: print(result)
15

EECS1015 – York University -- Prof. Michael S. Brown


Think like an interpreter (3/5)
Examine program step by step. line 6: result = processNum(num)
0: def processNum( x ) Data/Objects stored in memory
1: y = x**2 + 5*x – 2
List of variables
processNum(param: x) (function)
2: return y num 5 (integer)
3: result
4: num = input("Input number: ")
5: num = int(num)
6: result = processNum(num) Temporary Memory for function processNum()
7: print(result)
List of variables Data/Objects stored in memory
parameter: x 5 (integer)
y

step 1: A function is being called. result = processNum(num)


step 2: access data bound to num result = processNum(5)
step 3: access information about function processNum result = processNum(param: x)
- Python knows it has 1 parameter named x. 5
step 4: create temporary memory to store data for function
- make copy of argument (5) and place it into the
temporary memory. It will be bound to parameter x.
step 5: execute code in function. All variables in the function 1: y = x**2 + 5*x – 2
refer to the temporary (or local) memory. 2: return y
(cont' on next slide)
.. continue . . Think like an interpreter (4/5)
0: def processNum( x ) Data/Objects stored in memory
1: y = x**2 + 5*x – 2
List of variables
processNum(param: x) (function)
2: return y num 5 (integer)
3: result
4: num = input("Input number: ")
5: num = int(num) 48 (integer)
6: result = processNum(num)
7: print(result) Temporary Memory for function processNum()
List of variables Data/Objects stored in memory
parameter: x 5 (integer)
step 6: we are now inside the function! y 48 (integer)
We can think of this as a mini-program.
It has its own memory with variables. 6: result = processNum(param: x)
Inside function statements of processNum()
function - line 1:
step 1: replace bound data with parameter:x 1: y = x**2 + 5*x – 2
step 2: perform math and create new int object 48 y = (5)**2 + 5*(5) – 2
step 3: bind function variable y to 48 y = 48
function line 2: 2: return y
"return" statement makes a copy of data bound
Function is done – delete temporary memory.
to y to the memory space that called the function.
Proceed back at calling statement
step 7: Function is done. Delete temporary memory!
step 8: back to line 6 to bind result to 48. 6: result = processNum(param: x)
Continue Think like an interpreter (5/5)
0: def processNum( x )
1: y = x**2 + 5*x – 2
line 6: print out the data bound to result
2: return y
3: List of variables Data/Objects stored in memory
4: num = input("Input number: ")
processNum(param: x) (function)
num 5 (integer)
5: num = int(num)
6: result = processNum(num) result
7: print(result) 48 (integer)

When the function call is complete, the


Temporary Memory for function processNum()
temporary memory created while the
function was being executed is deleted. List of variables Data/Objects stored in memory
The value 48 computed is available parameter: x 3 (integer)
in the programs memory because y 48 (integer)
of the return statement in the function.
The Call Stack
• In the last example, we saw that when the function was executed,
Python created temporary memory to store the functions variables

• This temporary memory is created each time the function is called.

• The function's memory is stored on what is called the "Call Stack"

• See next slides for an example when multiple functions are called

EECS1015 – York University -- Prof. Michael S. Brown 19


Nested function calls
• Let's consider this program that has multiple function calls
• First look at the program and "trace" through the program flow

1: def func1(x):
2: y = x*x
3: return y

4: def func2(x):
5: y = func1(x)
6: y = y * 3
7: return y

8: def func3(x):
9: y = func2(x)
10: return y

11: x = func3(5)
12: print(x)

EECS1015 – York University -- Prof. Michael S. Brown 20


Function calls and the "Call Stack" (1/3)
Let's walk through Data/Objects stored in memory
List of variables
1: def func1(x): this program. func1(param: x) (function)
2: y = x*x We start at line 11 x func2(param: x) (function)
3: return y
which calls func3() func3(param: x) (function)
4: def func2(x): 5
11: x = func3(5)
5: y = func1(x)
6: y = y * 3 Python creates temporary memory for func3 local memory
7: return y func3(). This local memory is placed List of variables Data/Objects stored in memory
on what is called the "Call Stack".
8: def func3(x): Excuting code in func3() parameter: x 5
8: def func3(x):
9: y = func2(x) y
10: return y 9: y = func2(x)
func2 local memory

Call Stack
11: x = func3(5) 9: y = func2(x)
12: print(x) List of variables Data/Objects stored in memory
Python creates temporary memory for
func2() and places it on the "Call Stack". parameter: x 5
Executing code in func2() y
4: def func2(x):
5: y = func1(x)
func1 local memory
5: y = func1(x) List of variables Data/Objects stored in memory
Python creates temporary memory for
func1() and places it on the "Call Stack". parameter: x 5
Executing code in func1(x) y 21
1: def func1(x):
Function calls and the "Call Stack" (2/3)
List of variables Data/Objects stored in memory
func1(param: x) (function)
1: def func1(x): func2(param: x) (function)
2: y = x*x
12: print(x) x func3(param: x) (function)
3: return y
5
4: def func2(x): 75
11: x = func3(5)
5: y = func1(x)
6: y = y * 3 Inside func3 func3 local memory
7: return y 9: y is bound to return from function List of variables Data/Objects stored in memory
10: return 75 to calling function's memory
8: def func3(x): delete func3 local memory from the parameter: x 5
9: y = func2(x) "Call Stack" y 75
10: return y
9: y = func2(x) func2 local memory

Call Stack
11: x = func3(5) Inside func2
12: print(x) List of variables Data/Objects stored in memory
5: y is bound to return from function
6: compute y = y *3 5
parameter: x 25
7: return 75 to calling function's emory
y
delete func2 local memory from the 75
"Call Stack"
func1 local memory
Start reading 5: y = func1(x) List of variables Data/Objects stored in memory
here! Inside func1
2: Compute y=5*5 parameter: x 5
3: return 25 back to calling function's memory y 22
25
delete this memory from the "Call Stack"
Function calls and the "Call Stack" (3/3)
List of variables Data/Objects stored in memory
func1(param: x) (function)
1: def func1(x): func2(param: x) (function)
2: y = x*x x func3(param: x) (function)
3: return y
5
4: def func2(x): 75
5: y = func1(x)
6: y = y * 3
func3 local memory
Functions get their own Data/Objects stored in memory
7: return y List of variables
local memory each time
8: def func3(x): the function is called. Since parameter: x 5
9: y = func2(x) functions can call other y 75
10: return y functions, this local
memory is "stacked", that is func2 local memory

Call Stack
11: x = func3(5) why we use the term Stack.
12: print(x) List of variables Data/Objects stored in memory
5
Note that a return parameter: x
statement returns data 25
y
to the calling function's memory. 75
func1 local memory
When a function is complete,
List of variables Data/Objects stored in memory
it's local memory is
deleted from the call stack. parameter: x 5
y 23
25
Tracing the flow of the program
• Like conditional statements, functions also change the flow of the
program.
What is the flow of this program?
1: def func1(x):
See a trace of the line numbers.
2: y = x*x
3: return y
main program 11 main 12
4: def func2(x):
5: y = func1(x)
func3() 8, 9 func3() 10
6: y = y * 3 func2() 4,5 func2() 6, 7
7: return y
func1() 1, 2, 3
8: def func3(x):
9: y = func2(x)
10: return y

11: x = func3(5)
12: print(x)

EECS1015 – York University -- Prof. Michael S. Brown 24


Be careful with nested function calls
def func1(x): local memory
We have a nested function calls. Think func1() for func1()
y = x*2 about that this will do to the call stack?
y = func2(y) func1 call's func2
return y Will this program end? NO! local memory
for func2()
def func2(x): In Python, we will get a RecursionError, you have func2()
reached the maximum depth allowed. This means func2 call's func1
x = x+5
your "Call Stack" is full.
x = func1(x)
return x local memory
In other programming languages for func1()
we call this a "STACK OVERFLOW" func1()
func1(10) func1 call's func2

local memory
RecursionError: maximum recursion depth exceeded
func2() for func2()
func2 call's func1
This is very much like an infinite loop! This is an infinite function call.
The difference is in the function case you will eventually run out of Call Stack memory.

……….
EECS1015 – York University -- Prof. Michael S. Brown 25
https://trinket.io/python/d49638a319
Stack overflow
• Where did the name come from? See previous slide.
• Stack overflow is now known as one of the most useful websites
about programming
• Be careful with stack overflow, sometimes the answers are not
correct

EECS1015 – York University -- Prof. Michael S. Brown 26


Part 2: Global and Local Variables and
Variable Scope

EECS1015 – York University -- Prof. Michael S. Brown 27


Local vs Global variables
Global variables
List of variables Data/Objects stored in memory
0: def processNum( x ) processNum(param: x) (function)
1: y = x**2 + 5*x – 2 num 5 (integer)
2: return y result
3:
4: num = input("Input number: ") 48 (integer)
5: num = int(num)
6: result = processNum(num) Global variables are variables defined by the "main" program
7: print(result) outside any function.

The last examples we saw that functions


have their own memory. We can think Local variables for function processNum(x)
that these variables and their data are List of variables Data/Objects stored in memory
local to that function.
parameter: x 5 (integer)
y 48 (integer)
The main program has its own variable.
To distinguish these, we call the variables Local variables are variables defined and used by the function.
in the main program as "global" variables. Note that the parameter x can be treated as a variable.

EECS1015 – York University -- Prof. Michael S. Brown 28


Variable scope
• All variables inside a function (including the parameter variables) are
considered local
• Variable outside a function are global
• This introduces the notion of "variable scope"
• Because we can use the same name for global and local
def squareNum(num):
y = num * num Even though they have the same name, these variables
return y are different. The red num and y are locally scoped to the
function squareNum. The blue num and y are globally
y = 10 scoped to the main program.
num = squareNum(y)
https://trinket.io/python/3431aa159c

EECS1015 – York University -- Prof. Michael S. Brown 29


Functions accessing global variables
def computeArea(radius): def computeArea(radius):
area = radius**2 * PI Global PI PI = 3.14159 Local PI
return (area) area = radius**2 * PI
return (area)
PI = 3.15
r = 10 PI = 3.15
area = computeArea(r) r = 10
print("Area is : %.2f" % (area)) area = computeArea(r)
print("PI is %.4f" % (PI)) print("Area is : %.2f" % (area))
print("PI is %.4f" % (PI))

Area is : 315.00 Area is : 314.16


PI is 3.1500 PI is 3.1500
https://trinket.io/python/e9c5824853 https://trinket.io/python/8c4ab3703c

Global variables can be used by functions. However, in this example, since we have
In this case, the variable PI is being used in an assignment (or binding) operator in the function,
compute area. PI is treated as a local variable. Here we
see the output of the global variable PI
is not changed. That is because changing
the local variable PI in the function
EECS1015 – York University -- Prof. Michael S. Brown 30
has no effect on the global variable.
Global keyword to modify global data in a function
• It is possible for a function to access a global variable
• The keyword "global" can be added before a variable to specify it is
not local
def computeArea(radius):
global PI The keyword global allows
PI = 3.14159 this function to have access
area = radius**2 * PI to the global variable PI. PI
return (area) can now be modified and
the change will appear
PI = 3.15 outside the function.
r = 10
area = computeArea(r) This statement must be
print("Area is : %.2f" % (area)) made before the variable is
print("PI is %.4f" % (PI)) used.

Area is : 314.16
PI is 3.1416
EECS1015 – York University -- Prof. Michael S. Brown 31
Another example of using global keyword
def doSomething():
def doSomething():
global y
y = 15 This line of code will cause an In this example, since y is
y = 15
NameError. Why? Because not already a global variable,
doSomething() y is local to function this statement will create a
doSomething()
print(y) doSomething() only. global variable named y
print(y)
https://trinket.io/python/4b9bc57e2f
https://trinket.io/python/d4e8d482eb
print(y)
NameError: name 'y' is not defined
In this example, we have the statement "global y" in the
function. Because there isn't already a global variable
Variable y is defined inside the function doSomething(). named y, this will create a global variable. This
It is "local" to that function. It cannot be used outside code will not have an error.
the function. Where a variable can be accessed is
known as its "scope". This variable is locally scoped to
doSomething().

EECS1015 – York University -- Prof. Michael S. Brown 32


Be careful with global/local
def squareNum(x): def squareNum(x):
y = x * x global y
return y y = x * x
return y
def cubeNum(x):
y = squareNum(x) * x def cubeNum(x):
return y y = squareNum(x) * x
return y
y = 10
num = cubeNum(y) y = 10
print("%d**3 = %d" % (y, num)) num = cubeNum(y)
print("%d**3 = %d" % (y, num))
10**3 = 1000 100**3 = 1000
https://trinket.io/python/505a3b5496 https://trinket.io/python/2d1f5d2b4f
Here, we modified y in the squareNum function.
This makes the print out statement give
EECS1015 – York University -- Prof. Michael S. Brown an incorrect output. 33
A few more examples
def func(): def func(): def func():
a = 18 global a a = 18
b = 19 a = 18 global b
b = 19 b = 19
a = 10
b = 5 a = 10 a = 10
func() b = 5 b = 5
print("a=%d b=%d" % (a,b)) func() func()
print("a=%d b=%d" % (a,b)) print("a=%d b=%d" % (a,b))
a=10 b=5
a=18 b=5 a=10 b=19

def func():
global a, b
a = 18
b = a
Check these results and see if you understand
what makes them different?
a = 10
b = 5
func()
print("a=%d b=%d" % (a,b))

a=18 b=18
EECS1015 – York University -- Prof. Michael S. Brown 34
Part 3: Passing data, default arguments,
and returning data

EECS1015 – York University -- Prof. Michael S. Brown 35


Passing arguments by order
Passing by order Arguments passed to the function are bound to parameters by
the order the arguments appear when calling the function.
def studentRecord(name, number):
strFormat = "Name: '{}' Student Number: {}" studentRecord("Sascha", 203333995)
result = strFormat.format(name, number)
return result studentRecord(name, number)

output = studentRecord("Sascha", 203333995) Output:


print(output)
Name: 'Sascha' Student Number: 203333995

Passing by order Arguments passed to the function are bound to parameters by


def studentRecord(name, number): the order the arguments appear when calling the function.
strFormat = "Name: '{}' Student Number: {}" studentRecord(203333995, "Sascha")
result = strFormat.format(name, number)
return result studentRecord(name, number)

output = studentRecord(203333995, "Sascha")


print(output) Output:
Name: '203333995' Student Number: Sascha
For this example, we have the order wrong!
EECS1015 – York University -- Prof. Michael S. Brown 36
Passing arguments by keyword
Passing by keyword (parameter name)
def studentRecord(name, number): We can also explicitly use the name
strFormat = "Name: '{}' Student Number: {}" of the parameters with our arguments.
result = strFormat.format(name, number)
return result
This is known as passing by keyword
output = studentRecord(number=203333995, name="Sascha")
(or passing by name)
print(output)
Where have you seen this before?

studentRecord(number=203333995, name="Sascha")

studentRecord(name, number)
Output:
Name: 'Sascha' Student Number: 203333995

EECS1015 – York University -- Prof. Michael S. Brown 37


Passing by keyword
• If you decide to use pass by keyword, then all arguments must be
based by keyword, otherwise you'll get an error

def MyFunc(x, y, z):


w = x*y*z
return w

test(x=1, y=2, 3)

test(x=1, y=2, 3)
^
SyntaxError: positional argument follows
keyword argument

EECS1015 – York University -- Prof. Michael S. Brown 38


Default arguments
We can put in values in the parameter list to serve as default values.

def func( param1 = "Default", param2 = 10, param3=True, . . . ):




Function call signature when default arguments are used:

def myFunc(name, greeting="Hello")

call signature is two parameters, but only one must be given (name),
the other is optional (greeting) since it has a default value.

EECS1015 – York University -- Prof. Michael S. Brown 39


Default arguments
No default arguments Leaving out an argument causes an error
def greetingFunc(name, greeting): def greetingFunc(name, greeting):
print("{}: {}".format(greeting, name)) print("{}: {}".format(greeting, name))

greetingFunc("Mingnan", "Good morning") greetingFunc("Mingnan")

Good morning: Mingnan TypeError: greetingFunc() missing 1 required positional


argument: 'greeting'

Using default arguments (for one argument only) Using default arguments (for multiple arguments)
def greetingFunc(name, greeting="Hello"): def greetingFunc(name="Student", greeting="Hello"):
print("{}: {}".format(greeting, name)) print("{}: {}".format(greeting, name))

greetingFunc("Mingnan") greetingFunc()
greetingFunc("Abdel", "Good evening") greetingFunc("EECS class")
greetingFunc(greeting="Good afternoon")

Hello: Mingnan Hello: Student


Good evening: Abdel Hello: EECS class
Good afternoon: Student
Notice the last line of code used the keyword argument
approach. Why do you think that was necessary?
EECS1015 – York University -- Prof. Michael S. Brown 40
Multiple return statements
• Your function can have more than 1 return statement

# returns True if a is greater than b


# false if a <= b
def isMax(a, b):
if (a > b):
return True
else:
return False

EECS1015 – York University -- Prof. Michael S. Brown 41


Multiple return statements
• Just take care to make sure your code always returns a value

# returns True if a is great than b


# false if a <= b
def isMax(a, b):
if (a > b): What is wrong with this code?
return True
elif (a < b):
What happens is a==b?
return False

https://trinket.io/python/cfb46fe1b7

EECS1015 – York University -- Prof. Michael S. Brown 42


Returning multiple values
• Return statement can return multiple values
def computeSquareAndCube(x): def computeSquareAndCube(x):
sqred = x * x sqred = x * x
cubed = x * x * x cubed = x * x * x
return sqred, cubed return sqred, cubed
x=10
x_sq, x_cb = computeSquareAndCube(x) x_sq, x_cb = computeSquareAndCube(x)
print("%d %d %d" % (x, x_sq, x_cb)) def computeSquareAndCube(x):
sqred = x * x
y_sq = computeSquareAndCube(x)
print(y_sq) cubed = x * x * x
return sqred, cubed

10 100 1000
y_sq = computeSquareAndCube(x)
(100, 1000) (100, 1000) The return is multiple values
stored, but stored in a single variable.
This is called a "tuple" and we
https://trinket.io/python/4f3cbaa291
will learn about it in our next lecture.
EECS1015 – York University -- Prof. Michael S. Brown
43
Part 4: Modules
and special variable __name__

EECS1015 – York University -- Prof. Michael S. Brown 44


Organizing functions into a module
File: myInputFunctions.py
def getPositiveNumber(prompt="Input a positive number: "):
num = input(prompt)
num = int(num)
while (num < 0):
print(" Error: That isn't a positive number. ")
The code here shows three custom functions
num = input(prompt) that can be used to get different type of
num = int(num) numbers.
return num

The are all organized into this file named


def getNegativeNumber(prompt="Input a negative number: "): "myInputFunctions.py".
num = input(prompt)
num = int(num)
while (num >= 0):
This makes up a "module".
print(" Error: That isn't a negative number. ")
num = input(prompt)
num = int(num)
return num

def getNumber(prompt="Input a number: "):


str = ""
while (not str.isnumeric()):
str = input(prompt)
return– York
EECS1015 int(str)
University -- Prof. Michael S. Brown 45
Importing a module using import
File: myInputFunctions.py File: example.py
def getPositiveNumber(prompt="Input a positive number: "): import myInputFunctions
num = input(prompt) x = myInputFunctions.getPositiveNumber()
num = int(num) print(x)
while (num < 0):
print(" Error: That isn't a positive number. ") y = myInputFunctions.getNegativeNumber()
num = input(prompt) print(y)
num = int(num)
return num z = myInputFunctions.getNumber("NUM? ")
print(z)

def getNegativeNumber(prompt="Input a negative number: "):


num = input(prompt) The import keyword makes the functions
num = int(num) in myInputFunctions.py available
while (num >= 0): for the program in this python file (example.py).
print(" Error: That isn't a negative number. ")
num = input(prompt)
num = int(num) In order to use the functions, we have to specify
return num the modules name first as follows:
moduleName.functionName()
def getNumber(prompt="Input a number: "):
str = "" NOTE: It is customary, but not required, to
while (not str.isnumeric()): place "import" statements first in your python
str = input(prompt) Note: File "myInputFunctions.py"
return– York
int(str)
program.
EECS1015 University -- Prof. Michael S. Brownand "example.py" are in the same folder. 46
https://trinket.io/python/a10ee9e1d5
Importing a module as name
File: myInputFunctions.py Syntax
def getPositiveNumber(prompt="Input a positive number: "): import moduleName as newName
num = input(prompt)
num = int(num)
while (num < 0): Usages in code:
print(" Error: That isn't a positive number. ") newName.function()
num = input(prompt)
num = int(num) Adding "as newName" after the import
return num
changes the name needed to access the
functions. See code below.
def getNegativeNumber(prompt="Input a negative number: "):
num = input(prompt)
num = int(num)
File: example.py
while (num >= 0): import myInputFunctions as myInputs
print(" Error: That isn't a negative number. ") x = myInputs.getPositiveNumber()
num = input(prompt) print(x)
num = int(num)
return num y = myInputs.getNegativeNumber()
print(y)

def getNumber(prompt="Input a number: "): z = myInputs.getNumber("NUM? ")


str = "" print(z)
while (not str.isnumeric()):
str = input(prompt) https://trinket.io/python/11013531ed
return– York
EECS1015 int(str)
University -- Prof. Michael S. Brown 47
Import certain functions using from
• Our example is quite simple
• A module may have dozens of functions, the program importing the
module may only need to use a single function, or a few functions
• We can select which functions to import using the from keyword
Syntax:
from moduleName import functionName
from moduleName import functionName1, functionName2, … functionName3
from moduleName import * (the asterisk means import all – this is allowed, but is not considered good style)

Usage:
Note, when we use the from approach to import functions, we do not need to use use the
moduleName prefix before the function. See next slide.

EECS1015 – York University -- Prof. Michael S. Brown 48


Importing select functions
File: myInputFunctions.py Syntax
def getPositiveNumber(prompt="Input a positive number: "): from moduleName import funcName
num = input(prompt)
num = int(num)
while (num < 0): Usages in code:
print(" Error: That isn't a positive number. ") funcName()
num = input(prompt)
num = int(num) We can directly import a single function
return num from the module by giving its name.
We do not need to use the moduleName to
def getNegativeNumber(prompt="Input a negative number: "): access it.
num = input(prompt)
num = int(num)
File: example.py
while (num >= 0): from myInputFunctions import getPositiveNumber
print(" Error: That isn't a negative number. ")
num = input(prompt) # notice the name of the module is not
num = int(num) necessary
return num getPositiveNumber("Positive int: ")
print(x)

def getNumber(prompt="Input a number: "):


str = ""
while (not str.isnumeric()):
str = input(prompt)
return– York
EECS1015 int(str)
University -- Prof. Michael S. Brown 49
https://trinket.io/python/31c83dd533
More examples
Syntax:
from moduleName import functionName1, functionName2, … functionName3
from moduleName import * (the asterisk means import all – this is allowed, but is not considered good style)

from myInputFunctions import getPositiveNumber, from myInputFunctions *


getNumber
# notice the name of the module is not necessary
# notice the name of the module is not necessary x = getPositiveNumber("Positive int: ")
x = getPositiveNumber("Positive int: ") print(x)
print(x)
y = getNumber("NUM: ")
y = getNumber() print(y)
print(y)
z = getNegativeNumber("Negative int: ")
https://trinket.io/python/9910482e22 print(z)

https://trinket.io/python/baba392168

EECS1015 – York University -- Prof. Michael S. Brown 50


The __name__ variable
• Most programming languages have a special function that is the
starting point for the program
• (This function is typically called "main")

• Python starts with whatever file you run


• This file will be the main scope (or Global scope) for the program

• Python uses a special variable to allow you to determine if a file is


the file with main scope
• Two underscores _ _ name _ _

EECS1015 – York University -- Prof. Michael S. Brown 51


Example
from random import randint

def main():
str="" Code here only runs if this program
while (str.upper() != "Q"):
is the main program.
d1 = randint(1, 6)
d2 = randint(1, 6)
print("You rolled {} {} ".format(d1, d2))
str = input(" Press enter to roll again, q to quit ") This is a very common way you
if __name__ == "__main__":
will see Python code written.
main()
Why would we do this?

https://trinket.io/python/68b1739a0c

EECS1015 – York University -- Prof. Michael S. Brown 52


Consider the module example
File: myInputFunctions.py File continues here.
def getPositiveNumber(prompt="Input a positive number: "): if __name__ == "__main__":
num = input(prompt) print("Example of using module myInputFunctions")
num = int(num)
while (num < 0): print("Function 1: getPositiveNumber()")
print(" Error: That isn't a positive number. ") print("Keep inputting until an int >= 0 is provided")
num = input(prompt) print("Try an example")
num = int(num) x = getPositiveNumber()
return num print("The number is " + str(x))

print("Function 2: getNegativeNumber()")
def getNegativeNumber(prompt="Input a negative number: "): print("Keep inputting until an int < 0 is provided")
num = input(prompt) print("Try an example")
num = int(num) x = getNegativeNumber()
while (num >= 0): print("The number is " + str(x))
print(" Error: That isn't a negative number. ")
num = input(prompt) print("Function 3: getNumber()")
num = int(num) print("Keep inputting until a number is provided")
return num print("Try an example")
x = getNumber()
print("The number is " + str(x))
def getNumber(prompt="Input a number: "):
str = "" If this module is run as a
while (not str.isnumeric()): main program, we can have it
str = input(prompt)
return– York
EECS1015 int(str)
University -- Prof. Michael S. Brown
do a demo of the functions.
53
Part 5: Putting it all together

EECS1015 – York University -- Prof. Michael S. Brown 54


Task –Simple dice game
• Design a simple game of comparing two dice (user vs. computer)
• Ask the user to press enter to roll a dice
• Get the user's dice roll result
• Print the dice result out

• Ask the user to press enter to roll a dice for the computer
• Get the computer's dice roll result
• Print the result out

• If dice rolls are the same, you tie. Otherwise, if user's dice is larger – the user wins,
otherwise the user loses.

• Ask if they want to play again. If so, repeat the game. If not, stop the program

EECS1015 – York University -- Prof. Michael S. Brown 55


When to use functions
Sketch of program requirements We have freedom to design this program how we want.
• Ask the user to press enter to roll a dice Looking at the sketch of the game play, there are
• Get the user's dice several places where redundant functionality is required.
• Print the dice result out
If we need to do something multiple times, this is often
a good place to use a function.
• Ask the user to press enter to roll a dice for
the computer Looking at this code, I can identify a few functions
that would be useful.
• Get the computer's dice result
• Print the result out Potential functions:
(1) A function to prompt to run roll.
(2) A function to get the dice result (i.e., simulate a roll)
• If dice rolls are the same, you tie.
(3) A function to print out the dice
Otherwise, if user's dice is larger user wins,
otherwise the user loses. (4) A function to check result and printout win/lose/tie
(5) A function to ask if you want to play again

• Ask if they want to play again. If so, repeat It is clear we will need a while loop to have the game
the game. If not, stop the program run over and over.
EECS1015 – York University -- Prof. Michael S. Brown 56
Example solution – first define functions
# First, let's import a function from the module random # function to see who won and print out the results
from random import randint def checkGameResults(playerDice, computerDice):
print("-----------------------------------------")
if (playerDice < computerDice):
# function to get a key press. print("***Computer's is larger -- YOU LOSE!***")
def pressEnter(prompt="Press Enter "): elif (playerDice > computerDice):
input(prompt) print("***Your role is larger - YOU WIN!***")
else:
# simple function to simulate a dice roll print("***Dice are the same - YOU TIE!***")
# it returns a value between 1-6
def rollDice(): print("-----------------------------------------")
result = randint(1, 6)
return result

# function to check it player wants to play again


# this modifies the global variable keepPlaying
def playAgain():
global keepPlaying
str = input("Play again? (Y/N) ")
if (str.upper()=="Y"):
keepPlaying=True
else:
keepPlaying=False

EECS1015 – York University -- Prof. Michael S. Brown 57


program continues on next slide
Functions – print dice
def printDice(dice, message=""): elif dice == 4:
if (message!=""): print("""
print(message) _________
| |
| * * |
if dice == 1:
| |
print("""
| * * |
_________ |_________| """)
| |

function continues here


| |
| * | elif dice == 5:
| | print("""
|_________| """) _________
| |
elif dice == 2: | * * |
print(""" | * |
| * * |
_________
|_________| """)
| |
| * |
| | elif dice == 6:
| * | print("""
|_________| """) _________
| |
elif dice == 3: | * * |
print(""" | * * |
_________ | * * |
| | |_________| """)
| * |
| * |
| * |
|_________| """)
EECS1015 – York University -- Prof. Michael S. Brown 58 slide
program continues on next
Main program - main function
def main():
# define a global variable Everything in blue is a call to one
global keepPlaying
keepPlaying = True of our user-define functions.
print("---> TRY TO ROLL HIGHER THAN THE COMPUTER! <---")
while (keepPlaying): The red code is global variables.
pressEnter("Press enter to roll your dice!")
yourDice = rollDice()
printDice(yourDice, "YOUR ROLL!")
pressEnter("Press enter to let the computer roll! ")
computerDice = rollDice()
printDice(computerDice, "COMPUTER'S ROLL")
checkGameResults(yourDice, computerDice)
playAgain() # modifies the keepPlaying global

print("Thanks for playing!") # end of main()

#
# main entry point of program.
# Check if this is the main program
# if so, call the main function
if __name__ == "__main__":
main()

https://trinket.io/library/trinkets/94860c2307
EECS1015 – York University -- Prof. Michael S. Brown 59
Putting it all together
• One beautiful thing about programming is that you can have many
different designs that are all valid

• The example I provided shows one way to divide the program up


into functions

• Tried to show all the ideas in this topic – functions, global/local


scope, import, __name__, main

• This example did not use a user-defined module . . that will come
later.

EECS1015 – York University -- Prof. Michael S. Brown 60


Summary
• User defined functions help to organize your code
• We can organize functions into modules (or libraries) that can be used over
and over

• It takes time to learn the right way to break a program up into


functions

• Virtually all languages support functions and have the notion of local
and global variables

EECS1015 – York University -- Prof. Michael S. Brown 61

You might also like