CSc 250: Lecture Notes: scripting and functions in python

Review

Last lecture we spent a lot of time talking about variables and variable types, and printing. We also we using python in interactive mode only. Today, we will learn how to write a python script, in which we can write more complex programs.

Scripts

Everything we have done so far with python has been in interactive mode, where we use python in a shell environment. Most of the python we will write in this course (and that is written in the “real world”) is written in python script files and then executed.

A python script file is a text-based file with the extension .py.

As a super simple example, we will re-write the “Hello World” example in a python script, rather than in interactive mode. For starters, lets create a .py file to put the python code in.

Before doing this, we need to chose an editor to write our python code in. There are many options available for editing code in various languages. Python comes bundled with a very simple python editor/debugger called IDLE. I recommend using this is you are a beginner in python.

There are several ways to create an edit a new python file in idle, but I’ll show you how to do so directly from bash. First, cd into a directory that you want to keep your code in. For example:

$ pwd
/Users/username
$ mkdir test
$ cd test
$ pwd
/Users/username/test

Then run:

$ idle3 hello-world.py

Assuming idle is properly installed, this should open up a new window with a blank text file named hello-world.py.

Once the file is open, type the following and save the file:

print("Hello World")

Now open up a new terminal window, and cd /Users/username/test. If your run ls, you will see your file named hello-world.py. This python program can be executed by running python3 hello-world.py:

$ python3 hello-world.py 
Hello World

We executed the program, and Hello World was printed to stdout of bash. Cool! Lets add a few more python statements to hello-world.py and try rerunning it. Go back to your IDLE window, and add some likes to it, like so:

age = 45                          
DOB = "9.10.11"                   

print("Hello World!")  
print("How are you?") 
print("I am " + str(age) + " years old")
print("I was born on " + str(DOB))

Now when we run this program form bash, we will get:

$ python3 hello-world.py 
Hello World
How are you?
I am 45 years old
I was born on 9.10.11

Perhaps you can start to see why python programmers typically do not use interactive mode. Interactive mode can be useful for doing some quick math, or testing a python feature, but if you want to write useful and re-usable software in python, you should be writing your code in files.

Functions

In python, we can write functions that execute a particular operation. A function in python is similar to the mathematical notion of a function. Thus, before we start discussing python functions in detail, we should first review the concept of a function as a mathematical entity.

A function is an entity that takes zero or more value as input, and produces a particular output. The following diagram (from Wikipedia) is helpful in visualizing how functions work:

The domain of a function is the set of possible inputs that the function can take as input. The range of a function is the set of possible outputs the function can produce.

Let’s walk through a few examples.

ADDTHREE

Let’s create a function called ADDTHREE. As the name suggests, ADDTHREE will take a single number as input, and add 3 to it. The definition of ADDTHREE looks like:

ADDTHREE(x) = x + 3

Using this function:

ADDTHREE(3) = 3 + 3 = 6

ADDTHREE(17) = 17 + 3 = 20

In the case of ADDTHREE, the domain is all real numbers, and the range is also all real numbers.

How about another function?

MULDIV

Let’s make a function called MULDIV that multiplies a number by 7 and then divides by 2. The Definition is:

MULDIV(x) = (x * 7) / 2

And using it:

MULDIV(2) = (2 * 7) / 2 = 14 / 2 = 7

MULDIV(14) = (14 * 7) / 2 = 98 / 2 = 49

The domain and range are both all real numbers.

AVERAGE

Now we’ll make a function called AVERAGE that takes two arguments, and returns the average of the two. The Definition is:

AVERAGE(x, y) = (x + y) / 2

And using it:

AVERAGE(17, 19) = (17 + 19) / 2 = 36 / 2 = 18

AVERAGE(1234, 5678) = (1234 + 5678) / 2 = 6912 / 2 = 3456

The domain of this function is all pairs of real numbers. The range is all real numbers.

Combining Function

The results of functions can be combined with mathematical operators, like so:

AVERAGE(30, 50) + ADDTHREE(7) = ((30 + 50) / 2) + (7 + 3) = (80 / 2) + (10) = 40 + 10 = 50

MULDIV(20) + AVERAGE(20, 24) = ((20 * 7) / 2) + ((20 + 24) / 2) = (140 / 2) + (44 / 2) = 70 + 22 = 92

Composing Function

We can also compose functions. By this we mean that the result of one function can be used as an argument to the next function. The following diagram (also from Wikipedia) helps visualize this process:

Below are a few examples, using the functions we previously constructed:

MULDIV( ADDTHREE(17) ) = MULDIV( (17 + 3) ) = MULDIV(20) = (20 * 7) / 2 = 140 / 2 = 70

AVERAGE( ADDTHREE(37), MULDIV(10) ) = AVERAGE( (37 + 3), ((10 * 7) / 2) ) = AVERAGE(40, 35) = (40 + 35) / 2 = 75 / 2 = 37.5

Functions… in Python!

Now that we’ve reviewed the concept of a function as a mathematical entity, let’s talk about functions in python. As mentioned before, functions in python (and most programming languages) behave similarly to mathematical functions, though there are exceptions. A python function takes zero or more input arguments, and returns a result.

We can implement all three of the functions we discussed previously (ADDTHREE, MULDIV, and AVERAGE) in python.

ADDTHREE:

def add_three(x):
    return x + 3

def indicated that we are beginning the “definition” of a new function. add_three is the name of the function. Immediately following the name should be parenthesis (()), and within these is a comma-separated list of the names of the arguments. A colon must always be placed after the parenthesis (this is just a peculiarity of python, dont worry about the details of this for now).

The body of the function comes next. All functions bodies must be indented by four spaces. In bash, indentation was optional (though recommended for readability purposes). In python, indentation is strictly required in various scenarios, including when writing the body of a function. The function body contains the actual work that the function will accomplish. In this case, we just need to do a simple operation (add 3 to x).

The return keyword is used to specify the value that the function should return to who/what-ever invoked it. Thus, we put return immediately before x + 3, which is the value we need to return.

Now let’s look at MULDIV:

def mul_div(x):
    return (x * 7) / 2

And AVERAGE:

def average(x, y):
    return (x + y) / 2

Though all of the above examples are, functions are not limited to one python line/statement. Multiple statements can be put in the body of a function. This includes statements that declare variables, print to stdout, return values, and more! For example, average can be implemented more verbosely, using multiple lines of code:

def average(x, y):
    sum = x + y
    average = sum / 2
    return average

We can do a lot more with functions than just simple math. For example, we can write a function that prints strings stdout:

def print_person_info(name, address, email):
    print("Name:    " + str(name))
    print("Address: " + str(address))
    print("Email:   " + str(email))

This functions prints a summary of a person using the three input values.

Notice that in this function there is no return statement. In python, not all functions need to return a value. This is where a function in python differs from a typical mathematical function. These, by definition, must return a value. In “mathematical” words, a function not returning a value means that the function does not have a range.

However, this function still does something useful by printing some strings to stdout.

We will see, use, and write many functions throughout the remainder of the course, so you should get used to the syntax of writing a function. However, a function is not much use unless we can actually use it. So, how odes one use a function once it has been written? Here is a script called people-info.sh that defines and uses a function:

def print_person_info(name, employeeID, email):
    print('----------')
    print('Name:  ' + str(name))
    print('ID:    ' + str(employeeID)) 
    print('Email: ' + str(email))

print_person_info('Dan Drake', 123, 'dd@gmail.com')
print_person_info('Stan Clark', 578, 'clark@gmail.com')
print_person_info('Janet Alford', 777, 'jal@gmail.com')

In this script, we define a function similar to the one shown previously named print_person_info. This function takes three values as input (name, employeeID, and email), and prints a summary of them.

The last three lines of this script demonstrate how to call this function. Each of these lines represent an invocation of print_person_info. Calling a function is rather simple. Simply write the name of the function, and insert the values you want to pass to it, separated by comments. When this script is run, the following is the result:

$ python3 people-info.py 
----------
Name:  Dan Drake
ID:    123
Email: dd@gmail.com
----------
Name:  Stan Clark
ID:    578
Email: clark@gmail.com
----------
Name:  Janet Alford
ID:    777
Email: jal@gmail.com
$

You can also call one function from another function. This is demonstrated in the following modified version of people-info.py:

def print_separator():
    print('----------') 

def print_person_info(name, employeeID, email):
    print_separator()
    print('Name:  ' + str(name))
    print('ID:    ' + str(employeeID))
    print('Email: ' + str(email))

print_person_info('Dan Drake', 123, 'dd@gmail.com')
print_person_info('Stan Clark', 578, 'clark@gmail.com')
print_person_info('Janet Alford', 777, 'jal@gmail.com')

When run, this produces the same output:

$ python3 people-info-2.py 
----------
Name:  Dan Drake
ID:    123
Email: dd@gmail.com
----------
Name:  Stan Clark
ID:    578
Email: clark@gmail.com
----------
Name:  Janet Alford
ID:    777
Email: jal@gmail.com
$

Let’s write a function that computes the average of four numbers. This function will need to take four arguments (the four numbers). This number will return the average that we compute.

One way to implement this is:

def average_of_four_numbers(n1, n2, n3, n4):
    sum = n1 + n2 + n3 + n4
    average = sum / 4
    return average

We could also consolidate everything onto one line:

def average_of_four_numbers(n1, n2, n3, n4):
    return (n1 + n2 + n3 + n4) / 4

Both of these function will return the same value!

Let’s put this in a script called avg.py:

def average_of_four_numbers(n1, n2, n3, n4):
    sum = n1 + n2 + n3 + n4
    average = sum / 4 
    return average

avg = average_of_four_numbers(16, 32, 64, 128)

print('The average is: ' + str(avg))

An then run it!

$ python3 avg.py 
The average is: 60.0

We could also change the function to just print out the average directly, instead of returning the computed average to the caller.

def average_of_four_numbers(n1, n2, n3, n4):
    sum = n1 + n2 + n3 + n4
    average = sum / 4 
    print('The average is: ' + str(average))

average_of_four_numbers(16, 128, 256, 256)

When run, we will get:

$ python3 avg.py 
The average is: 164.0

Side-Effects

Notice that how in some of the functions we wrote above, the functions are able to have an effect outside of the function. For example, when a function prints a string to stdout, it is making a change to the environment outside of the body of the function. This is what is called a side-effect. Notice that this is another way that functions in python differ from a mathematical function. Mathematical functions cannot have “side effects.” They take zero or more inputs, do some operation on those inputs, and evaluate to (return) a result.

Printing text to stdout is one of several different types of side-effects that a function can cause. We will talk about other types of side-effects as we go along in the course.

Naming Conventions

At this point we have been working with both variables and functions. When declaring a new variable or defining a new function, we should be careful about how we name them. For one, you should always make sure that the names of variables and functions are descriptive. The name of a variable should clearly yet succinctly describe what the variable stores. The name of a function should clearly and succinctly describe the action that the function accomplishes.

There is also the issue of name formatting. So far in the lectures, we have stuck to naming variables and functions with all lower-case words. If a variable or function name contains multiple words, each is separated with an underscore. A few examples are:

This naming convention goes by several names:

These all basically mean the same thing, though.

Another common naming convention is called camelCase (or CamelCase). In the camelCase convention, each word used in the variable/function name begins with an upper-case letter, and the rest of the word is lower-case. This applies to all words in the name except for the first one, which should be all lower-case. A few examples are:

There are other conventions that software developers use as well, but these are the two most common. The official python style guide suggests using the underscore_separated convention for variables and functions. That’s what we will stick to in this class. On each programming assignment, a small number of points will be alloted to making sure your program is well structured, well documented, and has good “style.” A big part of having good style is naming things well, and naming things with consistent conventions.