functions - subprograms
concept and goals
• a group of statements identified by a name that
performs a computation
• goals:
• decomposition & abstraction: decompose the big problem
into smaller ones and hide the details of how a
computation is performed focusing on the provided
functionality
• reusability: write code once and reuse it every time the
computation is necessary
example
acquire two positive integer values n and k with
n >= k (to be verified and acquisition repeated
until n and k satisfy constraints) and compute the
number of combinations of n elements when taking k
items at a time
n n!
k k! * (n – k)!
solving algorithm
# acquire n
# acquire k
# check constraints and eventually repeat • abstract the
# compute factorial n functionality to
compute the
# compute factorial k factorial
# compute factorial (n-k) • re-use the
# compute result functionality easily
# display result
example
n = int(input())
while n < 0:
n = int(input())
k = int(input())
while k < 0 or n < k:
k = int(input())
fn = factorial(n)
fk = factorial(k)
fnk = factorial(n-k)
comb = fn // (fk * fnk)
print(comb)
example
n = int(input())
k = int(input())
while not (n >= 0 and k >= 0 and n >= k):
n = int(input())
k = int(input())
comb = factorial(n) // factorial(k) * factorial(n-k)
print(comb)
definition
def <name>(arg1, arg2,... argN):
<statements>
return res1, …, resM 0 or more
only when returning one or
more computed values to
the caller
arg1
res1
arg2
function resM
argN
example
def factorial(value):
if value >= 0:
res = 1
for i in range(2, value+1):
res = res * i
else:
res = -1 #a value that cannot be correct
return res
example
function: no argument, no result
example
function: no argument, a result
example
function: argument, a result
call
• when the function returns a value
<variable(s)> = <name>(arg1, … argN)
• when the function does not return a value
<name>(arg1, … argN)
arguments
• passed by assignment, effects depend on the passed
argument
• immutable -> no effect outside
• mutable -> effect
it passes the reference to the mutable object
arguments
• Positionals: matched from left to right
the normal case is to match passed argument values to
argument names in a function header by position, from
left to right
• Keywords: matched by argument name
callers can specify which argument in the function is
to receive a value by using name=value syntax
• Defaults: specify values for arguments that aren’t
passed
functions can specify default values for arguments to
receive if the call passes too few values using the
name=value syntax
arguments
<statements> def func(name, size):
func(value, dim) <statements>
<statements> def test(value, up=True):
func(name=value, size=dim) <statements>
example
def analyze_immutable(value): val = 10
print("inside sub 1") listval = [1,2,3,4,5]
print(value) print(val)
value += 1 analyze_immutable(val)
print(value) print("after sub 1")
print("-----------") print(val)
def analyze_mutable(values): print(listval)
print("inside sub 2") analyze_mutable(listval)
print(values) print("after sub 2")
values.append(100) print(listval)
print(values)
print("-----------")
example
10
inside sub 1
10
11
-----------
after sub 1
10
[1, 2, 3, 4, 5]
inside sub 2
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 100]
-----------
after sub 2
[1, 2, 3, 4, 5, 100]
scope
visibility of variables and functions
• global: visible/accessible to all elements, main
flow and subprograms
• local: visible/accessible only inside a subprogram
examples
global local
STOP = 5 <statements>
def fact(val):
def checkinput(): f = 1
sel = int(input()) for i in range(2,val+1):
while sel != STOP: f = f * i
<statements> <statements>
for i in range(0,n):
print(i, fact(i))
global vs local
• if a variable is assigned
inside a def, it is local to
that function.
• if a variable is assigned
in an enclosing def, it is
nonlocal to nested
functions.
• if a variable is assigned
outside all defs, it is
global to the entire file.
global vs local: careful!
mylst = [1, 2, 3, 4] i = …
def mybadfun(): def mybadfun(seq):
for elem in mylst: size = len(seq)
#do something while i < size:
<statements>
return statement
• subprograms return a single element using the
return statement
• it can return multiple values by packaging them in
a tuple or other collection type
base = 1
def multiple(x): p, newl = multiple(base)
y = x*2
r = [x, y] p, newl
return y, r (2, [1, 2])
guidelines
• Use global variables only when truly necessary
• A function should receive as arguments all and only
the information it needs to perform the computation
• Don’t change mutable arguments unless the caller
expects it
• Each function should have a single, unified purpose
• Each function should be relatively small
• One-line functions are not interesting