Worksheet: Building your own Python functions

Defining new Python functions

You have seen builtin functions, like type(), int(), str(), and functions from packages, like math.sqrt(). In Python, you can also define functions yourself. This is useful when you need to do the same thing (or something very similar) again and again. Suppose that you are in a country where temperature is given in Celsius, but you are more familiar with Fahrenheit. Here is how you can figure out that 20 degrees Celsius are 68 degrees Fahrenheit, and 30 degrees Celsius are 86 degrees Fahrenheit:

>>> print( (20 * 9/5) + 32)


>>> print( (30 * 9/5) + 32)


If you need to convert temperatures very often, this gets tedious. Instead, you can define your own function, similar to the way it is done in mathematics.

>>> def celsius_2_fahrenheit(temp):

...     print( temp * 9/5 + 32)


That is:

Note that the Python shell changes its prompt from ">>>" to "..." after the first line. This indicates that you are in the middle of defining something that is not finished yet. To show Python that you are finished with the function definition, hit "enter" on the second line of "...".

Note also that function definition uses a variable, temp. Python uses this variable in much the same way as in function definitions in mathematics:

f(x) = x+1

There, you don't have to specify beforehand what x is. Rather, for each x, the function value is f(x) = x+1. In the same way, when you call your function saying celsius_2_fahrenheit(20), then at this time, Python stores the value 20 in the variable temp and executes the code of the function with temp set to 20.

Now we can use the function:

>>> celsius_2_fahrenheit(20)


>>> celsius_2_fahrenheit(34)


When you define your function, you have to indent the second line using either "tab" or spaces. Why is that? It is because the indentation is what Python uses to figure out the length of the function definition. You could in principle also define functions that take up more than one line (and in future, you often will). Here is a somewhat contrived example:

>>> def celsius_2_fahrenheit(temp):

...     print(temp, "Celsius is:")

...     print(temp * 9/5 + 32, "Fahrenheit")


>>> celsius_2_fahrenheit(34)

34 Celsius is:

93.2 Fahrenheit

How does Python figure out how long the function definition is? By using the indentation. All the consecutive code that is indented the same number of spaces forms a block. It belongs together. In this case, it all forms a function definition together.

If you use different numbers of indentations, or if you don't use any indentation after the first line, Python complains.

>>> def celsius_2_fahrenheit(temp):

... print(temp * 9/5 + 32, "Fahrenheit")

  File "<stdin>", line 2

    print(temp * 9/5 + 32, "Fahrenheit")


IndentationError: expected an indented block

>>> def celsius_2_fahrenheit(temp):

...     print( temp, "Celsius is:")

...   print(temp * 9/5 + 32, "Fahrenheit")

    File "<stdin>", line 3

    print(temp * 9/5 + 32, "Fahrenheit")


IndentationError: unindent does not match any outer indentation level

Returning values

Many of the builtin functions that you have encountered return a value that you can store in a variable, or use further:

>>> wordlen = len("dynamic")

>>> wordlen


>>> len("dynamic") + len("ally")


That is, you can use len("dynamic") in expressions like you would the number 7. The function len() returns an integer, which we can see by inspecting wordlen:

>>> wordlen = len("dynamic")

>>> type(wordlen)

<class 'int'>

Our Celsius to Fahrenheit function, on the other hand, does not return any value:

>>> temp = celsius_2_fahrenheit(12)


>>> type(temp)

<class 'NoneType'>

This means that temp contains the special value None. If we want our function to return a value, we have to say so explicitly.

>>> def celsius_to_fahrenheit(temp):

...     return temp * 9/5 + 32


Note the new reserved Python word "return" in our function definition. It tells Python to return the given value. Now we can use the value returned by our temperature conversion function like we would any other floating point value:

>>> temp = celsius_to_fahrenheit(15)

>>> temp


>>> type(temp)

<class 'float'>

>>> celsius_to_fahrenheit(20)


>>> (celsius_to_fahrenheit(20) - 32) * 5/9


The command "return" means that a value is returned, and the function is terminated. That is, lines after "return" are completely ignored:

>>> def myfunc(x):

...     return 5*x-8

...     print( "this line is never executed.")


>>> myfunc(3)


As you can see, the string "this line is never executed" is not printed, so this line is, in fact, never executed.

Try it for yourself:

Functions with multiple arguments

So far we have only defined functions with one argument. Functions with multiple arguments are straightforward:

>>> def repeat_string(somestring, numtimes):

...     return somestring * numtimes


>>> repeat_string("hello ", 3)

'hello hello hello '

If you define a function and give a value for an argument in the definition, you can leave that argument off when calling the function. Or you can specify the argument to give it a different value from the default.

>>> def repeat_string(somestring, numtimes = 2):

...     return somestring * numtimes


>>> repeat_string(":) ", 5)

':) :) :) :) :) '

>>> repeat_string(":( ")

':( :( '

But you have to put all the arguments without default values before the ones with defaults.

>>> def repeat_string(somestring = "la", numtimes):

...     return somestring * numtimes


  File "<stdin>", line 1

SyntaxError: non-default argument follows default argument

The function print() also has arguments with default values. For example, the default separator between two things to print is a single space. But you can change that. ("" below is the empty string, the string with zero characters.)

>>> print("hello", "world")

hello world

>>> print("hello", "world", sep = "")


>>> print("hello", "world", sep = "  ??? ")

hello  ??? world

Executing a whole program at once

Another way of running your Python program is to use idle:


Whenever Python encounters the character #, it ignores the rest of the line. (Except when you use # inside a string, that is.) So this character is used to insert comments into code.

def repeat_string(somestring, numtimes = 2):

    # This function takes as arguments a string and an integer (default 2)

    # and returns a string: somestring, repeated numtimes times

    return somestring * numtimes

Where should you put comments?

Imagine yourself 3 months from now, trying to make sense of the code that you have written earlier. What pointers would you appreciate getting?

You can also use comments to temporarily deactivate code that you don't want to use at the moment.

def remove_whitespace(somestring):

    # return somestring.rstrip()

    return somestring.strip()