Creating functions in Python (Part 1)

Function definitions in Python

Translating from pseudocode to Python is straightforward: use "def" instead of "define", add a colon at the end of the function header, use return to return the value, like in pseudocode, make sure the function body is indented evenly, and end with a blank line to show that the definition is complete:

PseudocodePython
define name(one, two)
    return one
def name(one, two):
    return one
IndentIndent evenly
End functionEnd with a black line

As far as the computer is concerned, any amount of indentation is fine.

Python convention

Indent four spaces.

For consistency, the Python community has settled on the standard of four spaces.

Python convention

Separate functions with blank lines.

Another convention is to put a blank line before a function definition as well as after one. The reason for this is to make it clear which lines belong to the definition. A link to the standard conventions can be found on the help page.

Tricky parts about using function definitions

Remember ...

  • Make sure to end the function header line with a colon.
  • Indent evenly.
  • Avoid tabs (depending on the tool you use to enter code).
  • End with a blank line.

It is easy to forget the colon at the end of the line, until you see the error message. When indenting evenly, it is important not only for the lines to look even but to be even. This isn't a problem for Python panels in this course, but depending on what tools you use in the future, using tabs might cause problems. If you have one line indented with tabs and another with blank spaces, the computer will view them as not being evenly indented and hence not grouped together. This might result in mysterious behaviour that you can't understand. To make your code more readable, leave a blank line after a function to signal where it ends.

Glimpse of the future

  • Python uses colons.
  • Python uses indentation for grouping.

Keep in mind the idea of using colons and indented groups of lines - we will see them again.

Avoiding long lines

Once you start indenting lines of code, you'll find that sometimes text gets hard to read. This is especially true if an indented line of code wraps around to the next line on the screen, making the indentation hard to see.

Python convention

  • Allow no more than 79 characters on a line.
  • Use a backslash to continue a line.

Since most screens can display at least 79 characters on a line, the Python convention is to limit line lengths to 79. That is, if you have more than that many characters in one line of code, break it up by using more than one line, using a backslash, \, to indicate that the statement isn't yet finished:

print("Hello", "how are you", \
"and how is the weather?")
my_string = "Hello" + " how are you" + \
" and how is the weather?"

If the line break is between some type of brackets, the backslash is not necessary (optional). For example,

print("Hello", "how are you", 
"and how is the weather?")

Common errors

Let's define a simple function that adds two numbers and then squares them:

def f(x, y)
    z = (x + y) ** 2

This gives the following errors:

Traceback (most recent call last):
  File "<string>", line 1
    def f(x, y)
              ^
SyntaxError: invalid syntax

The error message is telling us that there is a syntax error but not what the error is. It shows where the error was detected, namely after the close parenthesis. To figure out the problem, we can go back to our syntax rules for defining functions and then we realize that there is a missing colon. So let's add a colon:

def f(x, y):
    z = (x + y) ** 2

We now run the program and observe that it does not output anything. Why didn't we get any output? Because we didn't ask for any! Remember, a function definition just defines the function. It does not call the function. So let's add a function call, making sure to leave a blank line to indicate where the function definition ends:

def f(x, y):
    z = (x + y) ** 2
    
f(1, 2)

When we run the program now, we still don't see any result. Why? Well, we've asked the computer to call the function on 1 and 2, but we haven't asked it to print the output. So let's print the result of the function call:

def f(x, y):
    z = (x + y) ** 2
    
print(f(1, 2))

Now we run our program and get the output None.

Our answer should be 9, not None! None is used by Python to indicate that there is a missing value. The value of a function call is what is returned. What did we return? Nothing! We can fix it by adding a return statement:

def f(x, y):
    z = (x + y) ** 2
return z
    
f(1, 2)

But now we have another error message:

 Traceback (most recent call last):
  File "<string>", line 3
SyntaxError: 'return' outside function

This is because the return statement was not indented and hence not part of the function body. So we fix the indentation, putting the return statement into the function body:

def f(x, y):
    z = (x + y) ** 2
    return z
    
f(1, 2)

Finally we have a working function that returns the output 9.

Summary

To summarize, here are some errors that are easy to make.

  • Missing colon can create errors. For example, forgetting the colon at the end of the function header generates an error:
    def f(x, y)
        return (x + y) ** 2
  • Missing return statement can create errors. For example,
    def f(x, y):
        z = (x + y) ** 2
  • Incorrect indentation can create errors. For example,
    def f(x, y):
        z = (x + y) ** 2
    return z

None is a built-in constant in Python. If you see the value None and weren't expecting that outcome, there is probably a mistake somewhere in your code. Remember that not every mistake leads to an error message, so you need to use whatever clues you have to figure out what went wrong.


Translating from pseudocode

To practice using the syntax for function definition, we start by translating the pseudocode for room painting into a Python function.

Pseudocode HEIGHT ← 10 define paint(rooms) big ← 8 * HEIGHT small ← 6 * HEIGHT one ← 2 * (big + small) return rooms * one
Python
HEIGHT = 10 # room height

def paint(rooms):
    big = 8 * HEIGHT
    small = 6 * HEIGHT
    one = 2 * (big + small)
    return rooms * one


The differences are small: equal signs, =, instead of arrows, , for assignment; def instead of define; a colon at the end of the function header; and a blank line at the end of the function definition.

Example: parking cost

Let's create a function for the parking cost example, making the number of days, 31, into a parameter. Recall that we wish to park a car for 31 days at a cost of $100 for each week and $20 a day for any extra days. The intermediate calculations we need is as follows:

  • Determine the number of weeks in 31 days.
  • Determine the number of days remaining.
  • Calculate cost of the weeks.
  • Calculate costs of days remaining.
  • Total the two costs.

Creating a function

Function definition recipe

  • Choose function and parameter names.
  • Choose the types of the parameters and the type of the output (if any).
  • Write the function header, which specifies the names.
  • Write the function body, the code for the function.

Using our function definition recipe, we first choose names for the function, say parking, and the parameter, say total_days:

Function: parking

Parameter: total_days

Input: integer

Output: integer

Since the number of days and the costs are integers, we'll design a function for which input and output are both integers.


Writing the function in Python

WEEK_CHARGE = 100 # cost per week
DAY_CHARGE = 20   # cost per day
DAYS_IN_WEEK = 7  # days per week

We'll identify which constants we'll need. We'll have one for the cost per week, one for the cost per day, and one for the number of days per week.


def parking(total_days):

Write the function header, remembering to start with def and end with a :.


    ## Determine number of weeks, days remaining
    weeks = total_days // DAYS_IN_WEEK
    days = total_days % DAYS_IN_WEEK

Figuring out the weeks and the days can be achieved by determining the quotient and the remainder for our parameter total_days and the constant daysinweek. We assign these to variables since we'll want to use them again later.


    week_cost = weeks * WEEK_CHARGE
    day_cost = days * DAY_CHARGE

The costs are determined by multiplying our results by the charges. Again, we assign the results to variables.


    return week_cost + day_cost

Finally, we return the sum of the two costs. Another option would have been to introduce a new variable to store the sum, and then to return the new variable. Both options are fine.

Here's our function when all parts are put together:

WEEK_CHARGE = 100 # cost per week
DAY_CHARGE = 20   # cost per day
DAYS_IN_WEEK = 7  # days per week    

def parking(total_days):
    ## Determine number of weeks, days remaining
    weeks = total_days // DAYS_IN_WEEK
    days = total_days % DAYS_IN_WEEK

    ## Calculate cost of weeks, days remaining
    week_cost = weeks * WEEK_CHARGE
    day_cost = days * DAY_CHARGE

    ## Total two costs
    return week_cost + day_cost