Reader small image

You're reading from  Scientific Computing with Python 3

Product typeBook
Published inDec 2016
Reading LevelBeginner
PublisherPackt
ISBN-139781786463517
Edition1st Edition
Languages
Right arrow
Authors (3):
Claus Führer
Claus Führer
author image
Claus Führer

Claus Führer is a professor of scientific computations at Lund University, Sweden. He has an extensive teaching record that includes intensive programming courses in numerical analysis and engineering mathematics across various levels in many different countries and teaching environments. Claus also develops numerical software in research collaboration with industry and received Lund University's Faculty of Engineering Best Teacher Award in 2016.
Read more about Claus Führer

View More author details
Right arrow

Chapter 7. Functions

This chapter introduces functions, a fundamental building block in programming. We show how to define them, how to handle input and output, how to properly use them, and how to treat them as objects.

Basics


In mathematics, a function is written as a map that uniquely assigns an element y from the range R to every element x from the domain D.

This is expressed by f : D → R

Alternatively, when considering particular elements x and y, one writes f : x → y

Here, f is called the name of the function and f(x) is its value when applied to x. Here, x is sometimes called the argument of f. Let's first look at an example before considering functions in Python.

For example, D = ℝ x ℝ  and y = f(x1, x2) = x1 - x2 . This function maps two real numbers to their difference.

In mathematics, functions can have numbers, vectors, matrices, and even other functions as arguments. Here is an example of a function with mixed arguments: 

.

In this case, a number is returned. When working with functions, we have to distinguish between two different steps:

  • The definition of the function
  • The evaluation of the function, that is, the computation of f(x) for a given value of x

The first step is done once, while the second...

Parameters and arguments


When defining a function, its input variables are called the parameters of the function. The input used when executing the function is called its argument.

Passing arguments - by position and by keyword

We will consider the previous example again, where the function takes two parameters, namely x1 and x2.

Their names serve to distinguish the two numbers, which in this case cannot be interchanged without altering the result. The first parameter defines the number from which the second parameter is subtracted. When subtract is called, every parameter is replaced by an argument. Only the order of the arguments matters; the arguments can be any objects. For instance, we may call the following:

z = 3 
e = subtract(5,z)

Besides this standard way of calling a function, which is by passing the arguments by position, it might sometimes be convenient to pass arguments using keywords. The names of the parameters are the keywords; consider the following instance:

z = 3 
...

Variable number of arguments


Lists and dictionaries may be used to define or call functions with a variable number of arguments. Let's define a list and a dictionary as follows:

data = [[1,2],[3,4]]    
style = dict({'linewidth':3,'marker':'o','color':'green'})

Then we can call the plot function using starred (*) arguments:

plot(*data,**style)

A variable name prefixed by * , such as *data in the preceding example, means that a list that gets unpacked in the function call is provided. In this way, a list generates positional arguments. Similarly, a variable name prefixed by **, such as **style in the example, unpacks a dictionary to keyword arguments. Refer to the following figure (Figure 7.1):

Figure 7.1: Starred arguments in function calls

You might also want to use the reverse process, where all given positional arguments are packed into a list and all keyword arguments are packed into a dictionary when passed to a function.

In the function definition, this is indicated by parameters prefixed...

Return values


A function in Python always returns a single object. If a function has to return more than one object, these are packed and returned as a single tuple object.

For instance, the following function takes a complex number z and returns its polar coordinate representation as magnitude r and angle  according to Euler’s formula:

And the Python counterpart would be this:

def complex_to_polar(z):
    r = sqrt(z.real ** 2 + z.imag ** 2)
    phi = arctan2(z.imag, z.real)
    return (r,phi)  # here the return object is formed

Here, we used the sqrt(x) NumPy function for the square root of a number x and arctan2(x,y) for the expression tan-1(x/y).

Let us try our function:

z = 3 + 5j  # here we define a complex number
a = complex_to_polar(z)
r = a[0]
phi = a[1]

The last three statements can be written more elegantly in a single line:

r,phi = complex_to_polar(z)

We can test our function by calling polar_to_comp; refer to Exercise 1.

If a function has no return statement...

Recursive functions


In mathematics, many functions are defined recursively. In this section, we will show how this concept can be used even when programming a function. This makes the relation of the program to its mathematical counterpart very clear, which may ease the readability of the program.

Nevertheless, we recommend that you use this programming technique with care, especially within scientific computing. In most applications, the more straightforward iterative approach is more efficient. This will become immediately clear from the following example.

Chebyshev polynomials are defined by a three-term recursion:

Such a recursion needs to be initialized, that is, T0(x) =1, T1(x) = x.

In Python, this three term recursion can be realized by the following function definition:

def chebyshev(n, x):
    if n == 0:
        return 1.
    elif n == 1:
        return x
    else:
        return 2. * x * chebyshev(n - 1, x) 
                      - chebyshev(n...

Function documentation


You should document your functions using a string at the beginning. This is called docstring:

def newton(f, x0):
    """
    Newton's method for computing a zero of a function
    on input:
    f  (function) given function f(x)
    x0 (float) initial guess 
    on return:
    y  (float) the approximated zero of f
    """
     ...

When calling help(newton), you get this docstring displayed together with the call of this function:

Help on function newton in module __main__:

newton(f, x0)
     Newton's method for computing a zero of a function
     on input:
     f  (function) given function f(x)
     x0 (float) initial guess
     on return:
     y  (float) the approximated zero of f

The docstring is internally saved as an attribute, __doc__, of the given function. In the example, it's newton.__doc__. The minimal information you should provide in a docstring is the purpose of the function...

Functions are objects


Functions are objects, like everything else in Python. One may pass functions as arguments, change their names, or delete them. For example:

def square(x):
    """
    Return the square of x
    """
    return x ** 2
square(4) # 16
sq = square # now sq is the same as square
sq(4) # 16
del square # square doesn't exist anymore
print(newton(sq, .2)) # passing as argument

Passing functions as arguments is very common when applying algorithms in scientific computing. The functions fsolve  in scipy.optimize for computing a zero of a given function or quad in scipy.integrate for computing integrals are typical examples.

A function itself can have a different number of arguments with differing types. So, when passing your function f to another function g as argument, make sure that f has exactly the form described in the docstring of g.

The docstring of fsolve  gives information about its func parameter:

func -- A Python function or...

Anonymous functions - the  lambda keyword


The keyword lambda is used in Python to define anonymous functions, that is; functions without a name and described by a single expression. You might just want to perform an operation on a function that can be expressed by a simple expression without naming this function and without defining this function by a lengthy def block.

Note

The name lambda originates from a special branch of calculus and mathematical logic, the -calculus.

For instance, to compute the following expression, we may use SciPy’s function quad, which requires the function to be integrated as its first argument and the integration bounds as the next two arguments:

Here, the function to integrate is just a simple one-liner and we use the lambda keyword to define it:

import scipy.integrate as si
si.quad(lambda x: x ** 2 + 5, 0, 1)

The syntax is as follows:

lambda parameter_list: expression

The definition of the lambda function can only consist of a single expression and in particular...

Functions as decorators


In the partial application section, we saw how a function can be used to modify another function. A decorator is a syntax element in Python that conveniently allows us to alter the behavior of a function without changing the definition of the function itself. Let us start with the following situation:

Assume that we have a function that determines the degree of sparsity of a matrix:

def how_sparse(A):
    return len(A.reshape(-1).nonzero()[0])

This function returns an error if it is not called with an array object as input. More precisely, it will not work with an object that does not implement the reshape method. For instance, the how_sparse function will not work with a list, because lists have no reshape method. The following helper function modifies any function with one input parameter so that it tries to make a type conversion to an array:

def cast2array(f):
    def new_function(obj):
        fA = f(array(obj))
        return fA
    return...

Summary


Functions are not only the ideal tools for making your program modular, but they also reflect mathematical thinking. You learned the syntax of function definitions and to distinguish between defining and calling a function.

We considered functions as objects that can be modified by other functions. When working with functions, it is important to be familiar with the notion of the scope of a variable and how information is passed into a function by parameters.

Sometimes, it is convenient to define functions on the fly with so-called anonymous functions. For this, we introduced the keyword lambda.

Exercises


Ex 1 → Write a function polar_to_comp, which takes two arguments r and and returns the complex number Use the NumPy function exp for the exponential function.

Ex 2 → In the description of the Python module functools, (refer to [8] for more detail on functools) you find the following Python function:

def partial(func, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = keywords.copy()
        newkeywords.update(fkeywords)
        return func(*(args + fargs), **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc

Explain and test this function.

Ex 3 → Write a decorator for the function how_sparse,  which cleans the input matrix A by setting the elements that are less than 1.e-16 to zero (consider example in section Function as decorators).

Ex 4 → A continuous function f with f(a)f(b) < 0 changes its sign in the interval [a, b] and has at least one root...

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Scientific Computing with Python 3
Published in: Dec 2016Publisher: PacktISBN-13: 9781786463517
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime

Authors (3)

author image
Claus Führer

Claus Führer is a professor of scientific computations at Lund University, Sweden. He has an extensive teaching record that includes intensive programming courses in numerical analysis and engineering mathematics across various levels in many different countries and teaching environments. Claus also develops numerical software in research collaboration with industry and received Lund University's Faculty of Engineering Best Teacher Award in 2016.
Read more about Claus Führer