from IPython.core.display import HTML

HTML(open("custom.html", "r").read())
Creative Commons License This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Copyright (C) 2014-2023 Scientific IT Services of ETH Zurich,
Contributing Authors: Uwe Schmitt, Mikolaj Rybniski

3. Python functions¶

The general syntax to define a function in Python is:

def <name>(<arg_0>,...):
    <body>

There are no curly braces to delimit the body of the function and there is also no statement like end or enddef to indicate the end of the body. Instead Python uses indentation:

For example:

def print_squared(x):
    print(x, "squared is", x * x)
print_squared(42)
42 squared is 1764

This is an example for a function without arguments, and a function body which consists of multiple lines. all lines with same indentation form the body of the function:

def say_hello():
    print("hello")
    print("how do you do !")
    print("nice weather, eh ?")


print("hi")  # this is now outside the function definition!
hi
  • as soon as indentation decreases the body of the function is completed.
  • no curly braces
  • no "end" or similar statements
  • this applies also for branches and loops (more about this later)
say_hello()
hello
how do you do !
nice weather, eh ?

Good style:¶

  1. use four spaces (or multiples) for indentation
  2. no TABs (most IDEs and jupyter automatically replace TAB by spaces!). But be careful if you use plain text editors like vim!

Return statement¶

To return a computed value return is used. Parenthesis around the return value are not required!

def times_3(x):
    return 3 * x
print(times_3(7))
21

A missing or plain return statement returns None which is usualy interpreted as "undefined":

def do_nothing(x):
    return


def print_x(x):
    print("x is", x)


print(do_nothing(0))
None
print(print_x(1))
x is 1
None

Dynamic type checking¶

Python does not require type declaration for the arguments. During execution of the function Python determines if operations on arguments fit:

print(times_3("ab"))
ababab

This concept is also called duck typing: "If it walks like a duck and it quacks like a duck, then it must be a duck" (see also https://en.wikipedia.org/wiki/Duck_typing)

Python supports multiple return values:¶

def sum_and_diff(x, y):
    sum_ = x + y
    diff = x - y
    return sum_, diff

The previous function returns two numbers.

The caller of the function then also must fetch both values as follows:

a, b = sum_and_diff(7, 3)

print("sum is", a)
print("diff is", b)
sum is 10
diff is 4

This works for an arbitrary number of return values.

Python doc strings¶

The first string after def is called "doc string" and is the preferred way to document your functions. The doc-string is also visible when you use help:

def average_3(a, b, c):
    """this function computes the average of
    three given numbers
    """
    return (a + b + c) / 3.0


help(average_3)
Help on function average_3 in module __main__:

average_3(a, b, c)
    this function computes the average of
    three given numbers

A few words about execution order¶

def fun():
    print("i am fun")
    gun()


def gun():
    print("i am gun")


fun()
i am fun
i am gun

Calling gun within fun works, to understand this we follow the order of execution:

  1. Python interpreter starts to execute script at first line
  2. then Python interpreter sees declaration of fun and stores function name and start of end of function body.
  3. then Python interpreter sees declaration of gun and stores function name and start of end of function body.
  4. then Python interpreter sees call of fun, because of step 1 the interpreter knows where the body of fun starts and thus starts to execute the corresponding code lines.
  5. After the print("i am fun") Python interpreter sees call of gun and again: because of step 2 the interpreter knows where the body of gun starts and thus starts to execute the corresponding code lines.

Default arguments (when defining a function)¶

You can declare functions with different number of arguments:

def greet(name, formula="hi", ending="?"):
    print(formula, name, "how do you do", ending)


# this uses the default value "hi" for the second argument:
greet("uwe")

# and this overruns the first default argument:
greet("urs", "gruezi")

# and this one overungs all:
greet("buddy", "yo", "\o/")
hi uwe how do you do ?
gruezi urs how do you do ?
yo buddy how do you do \o/

Naming arguments (when calling a function)¶

Default arguments use = during function declaration. You can also name parameters with = when calling a function, so you do not have to remember the order and your code is better readable as you need not to look up the meaning of parameters:

greet("urs", ending="???", formula="gruezi wohl")
gruezi wohl urs how do you do ???

Another example:

# declare function with default arguments as seen above:
def exchange_chf_to_eur(money, bank_discount=0.02, rate=1.2):
    return money * rate * (1.0 - bank_discount)


print(exchange_chf_to_eur(100.0, rate=1.05))
102.89999999999999
print(exchange_chf_to_eur(rate=1.05, money=200.0, bank_discount=0.01))
207.9

Exercise Session 3¶

  1. Reread the examples above carefully.
  2. Type and run the exchange_chf_to_eur example.

Check questions¶

Please try to answer the following question using pen and paper. You can afterwards check your results by writing and running code:

  1. What is the value of z in the following code?

    def func(a, b=2, c=3):
        a += c
        return a * b, a / b, 2 ** c
    
    u, v, w = func(7, c=1)
    
    z = u / v + w
    
    
    

Programming exercises¶

  1. Write a function which takes the diameter of a circle and returns its area and circumference

Homework¶

  1. Write a function which takes 1 up to 3 values and computes their product:

    product(2) returns 2
    product(2, 3) returns 6
    product(2, 3, 4) returns 24
    

Optional exercises*¶

Functions operating on functions are also called "higher order functions" and this can be applied recursively.

Try to follow and understand the following examples.

E.g.We can pass functions as function arguments, so try to understand what the following functions do:

import math


def avg_at_1_2(f):
    return (f(1) + f(2)) / 2.0


print(avg_at_1_2(math.sqrt))
1.2071067811865475

We can also implement a function which returns a function:

def incrementor(by):
    def increment(x):
        return x + by

    return increment


inc = incrementor(1)
print(inc(4))
5

Or a function which takes two functions and returns another one:

def compose(f, g):
    def f_after_g(x):
        return f(g(x))

    return f_after_g


f = compose(math.exp, math.log)
print(f(3))

f = compose(math.sqrt, math.asin)
print(f(1.0))
3.0000000000000004
1.2533141373155001