Introductory exercices: Functions

Heaviside function

Write a function that returns the Heaviside function.


In [ ]:
def heaviside(x):
    #finish

#check it
print(heaviside(-5.4), heaviside(7), heaviside(0))

Prod

Python has a function sum that sums the elements of a list. Write a function that calculates the product of all the elements of a list.


In [ ]:
def prod(x):
    """
    sum(iterable) -> value
    """
    #Finish

#Test it
prod([1,2,3])

Sum has an optional argument. Implement the same optional argument in your function.


In [ ]:
def prod(x, start = 1):
    """
    sum(iterable[, start]) -> value
    
    Return the product of an iterable of numbers (NOT strings) times the value
    of parameter 'start' (which defaults to 1).  When the iterable is
    empty, return start.
    """
    # Finish

prod([1,2,3], 10)

Sum of lists

If you have 2 lists, a and b, a+b does not add the elements of the list. Write a function that does that. There is already a python function called sum. Try what happens if you call your function sum. The zip function can be helpful. Try zip([1,2,3], [4,5,6]).


In [ ]:
def lists_sum(a,b):
    #Finish

lists_sum([4,3,2], [4,1,3])

Prime numbers

Write a module that implements a function that returns all the prime numbers up to a limit. (Use the Sieve of Erastothenes method)


In [ ]:
def primes_sieve_list(limit):
    #Do it...


# see also http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Python

Optional and default arguments

Imagine a function to submit jobs to a queue. Here you see its first lines.


In [ ]:
def submit(job, priority=10, nprocs=1):
    print("Job {} submitted with priority {} and {} processors.".format(job, priority, nprocs))
    # And here you would do the actual submission...

Try to predict and understand the output of these calls to the function:


In [ ]:
submit()
submit('job1')
submit('job1', nprocs=5)
submit('job1', 5)
submit('job1', 5, nprocs=2)
submit('job1', 5, priority=5)

The follwing function uses argument unpacking. This is a powerful technique.


In [ ]:
def print_args(*args, **kwargs):
    for i, arg in enumerate(args):
        print('positional argument {} = {}'.format(i,arg))
    for key in kwargs:
        print('keyword argument {} = {}'.format(key, kwargs[key])

Call this function with different arguments and understand its output:

print_args(), print_args(5,6,5), print_args([5,4]), print_args(time = 0.0), print_args('a', b', c='c'), print_args(c = 'c', 'a', 'b'),print_args('a', c = 'c', 'b'), etc.

We have not covered all the possibilities of function arguments. Check the documentation for things link forcing the use of only keyword arguments.


In [ ]:

Tricky default arguments

The use of default mutable arguments is a source of confusion for novice Python users. Imagine you need to write a function that has an optional argument, which is a list. This function appends something to that list, or creates it if called without arguments. A naive approach would be:


In [ ]:
def f(data=[]):
    data.append(1)
    return data

Call it several times (with a without arguments) and see what happens. Execute it in Pythontutor and see if you can understand better the behaviour. This blog entry gives a further explanation. The main idea is that the def statement is executed when the function is defined:


In [ ]:
def f(x):
    print("In f(x), x =",x)
    return x*2

def g(x=f(3)):
    print("In g(x), x =",x)
    return None

In [ ]:
g()

Now you should be able to predict the result of this cell (example from here):


In [ ]:
fruits = ("apples", "bananas", "loganberries")
def eat(food=fruits):
    print(food)

eat()
fruits = ("blueberries", "mangos")
eat()

But how is this solved? How to create an empty list of dictionary as a default argument. Here is a way to do it:


In [ ]:
def f(data=None):
    if data is None:
        data = []
    data.append(1)
    return data