# 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)

68.0

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

86.0

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:

• "def", which tells Python that you're defining a function

• The name of the function, celsius_2_fahrenheit, which is another variable that you define

• The argument of the function in round brackets

• and a colon

• Then, in the next line, indent by hitting "tab"

• then define what the function does

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)

68.0

>>> celsius_2_fahrenheit(34)

93.2

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

7

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

11

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)

53.6

>>> 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

59.0

>>> type(temp)

<class 'float'>

>>> celsius_to_fahrenheit(20)

68.0

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

20.0

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)

7

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:

• Define a function that converts degrees Fahrenheit to degrees Celsius (for the benefit of Europeans like me). Make the function return, rather than print, the result

• Define a function that takes a string as input, converts it to a floating point number and adds 3.14 to it. Make the function return the result. (For now, just assume that the string can be converted to a number successfully.)

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 = "")

helloworld

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

hello ??? world

Executing a whole program at once

• In it, write the following very short Python program:

• print("Hello world!")

• Save the file as first.py, making sure to save it as text only!

• On a command line -- that is, not in a Python shell, but in a fresh terminal--, type

• python3 first.py

• Depending on which directory you used to store first.py, you will have to type that directory name in front of "first.py".

• If you are running Unix, this probably sounds straightforward to you. For instructions on how to execute a Python script under Windows, see http://docs.python.org/faq/windows.html#how-do-i-run-a-python-program-under-windows

• Note: Windows needs to know where Python is located on your machine in order to execute Python scripts. You let it know where Python is by modifying the Environment Variable "PATH". Here is a good explanation how to do this (the above link does not help much): http://www.imladris.com/Scripts/PythonForWindows.htmlhttp://www.imladris.com/Scripts/PythonForWindows.html

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

• Start up idle

• Then in the "Run" menu, choose "Run module".

• You should be able to see the output of your program in the idle shell now.

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

• At the beginning of your program: Who wrote it? When? What does it accomplish?

• At the beginning of each function: What are the arguments? What does the function return? What does it do?

• At other places in the code, whenever you are doing something nonobvious.

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()