/ 100DaysOfPython

Day 11: Functions in Python

How did it go in yesterday’s challenge? What we’ll learn today will make a lot of sense in the context of what you’ve been working on.


This post is part of #100DaysOfPython, check out yesterday's post here if you haven't already. Or go to the index of all 100 days.


Here’s a potential solution to the challenge:

students = [
  { "name": "Jose", "marks": [56, 77, 97] },
  { "name": "Rolf", "marks": [45, 80] },
  { "name": "Anna", "marks": [87, 75, 100, 95, 98] },
  { "name": "Mary", "marks": [67, 70, 80] },
  { "name": "Stuart", "marks": [44, 55] },
  { "name": "Sophie", "marks": [86, 90, 100, 100] },
]

total = 0
count = 0

for student in students:
  total += sum(student['marks'])
  count += len(student['marks'])

print(total / count)

If you run that code, it should return something like 79.05263157894737.

Functions

Functions in Python are names for blocks of code. You can define a few lines of code, give them a name, and then whenever you invoke that name the lines of code will run.

calling a function is the same as invoking it or running it.

For example:

def my_function():
    print("Hello")

If we type that into a file and run it, we won’t see anything. It’ll just terminate without printing ”Hello”. That’s because defining the function doesn’t run it. We must call it.

def my_function():
    print("Hello")

my_function()

We’ve now added the function call, which is just the name of the function and the pair of brackets—but not the def keyword or the colon, :.

As soon as we call the function, Python jumps to the first line inside the function (which is below the colon and indented). When the function ends, it continues on the next line after the original function call.

What are the brackets for?

In any function, the brackets are to enclose any values we want to give the function. Any function can take parameters if it is defined to do so. For example, the following two functions:

def add_two(x, y):
    print(x + y)

def hi():
    print("Hello")

The add_two function has two parameters called x and y. That means that inside the function we can use x and y as if they were variables defined inside the function.

But what are the values of x and y?

We give values to the function as arguments when we call the function. For example:

add_two(13, 45)  # prints 58

In this example, x = 13 and y = 45.

Notice that if you give arguments to a function that accepts no parameters, you’ll get an error!

hi(45)  # TypeError: hi() takes 0 positional arguments but 1 was given

The same problem happens if you give the wrong number of arguments to a function, even if it does accept some arguments.

Arguments vs Parameters?

Parameters are the “variables” defined inside the function as values it will accept. Arguments are the values that we give it when we call it.

You could say that for each parameter, its value is that of the corresponding argument.

The concept of scope

Scope in Python is very important—you'll be learning a lot about it over the next 89 days.

A function has scope, and that means there are variables which can only be accessed within the function, and not outside. Any variable defined inside a function will cease to exist once the function has finished running.

For example, let's take our add_two() function:

def add_two(x, y):
    print(x + y)

add_two(43, 21)
print(x)

What do you think we would see output to the console?

The first thing we do is define a function which prints the sum of its parameters. Defining the function doesn't call it, so we would see nothing until line 3 runs.

add_two(43, 21) calls the function, and we'd see 64 printed out.

print(x) tries to access the variable x, but because the variable is created inside the function, it is no longer available outside the function.

We would get a NameError, with an accompanying message: NameError: name 'x' is not defined. The variable we tried to access didn't exist when we tried to access it; it had already been destroyed by Python in order to be more efficient.

Functions returning values

Functions are not limited to printing their output. They can return values so that the caller can use it. Here’s an example:

def add_two(x, y):
    return x + y

def p_add_two(x, y):
    print(x + y)

n1 = add_two(13, 45)
n2 = p_add_two(13, 45)

What do you think the values of n1 and n2 would be?

Because add_two returned a value, n1 equals 58.

Because p_add_two did not return a value, n2 equals None. All functions in Python return None if nothing else is returned. It’s a special value in Python that means “nothing”.

Notice that p_add_two did print something out to the console, whereas add_two did not. We would see something only when calling p_add_two. We wouldn’t see anything when we call add_two, but we would then have access to the returned value!

Functions in yesterday’s challenge

At the start of this post I mentioned that functions would make a lot of sense in the context of yesterday’s challenge. Let’s take a look at the solution I proposed at the start of the post:

students = [
  { "name": "Jose", "marks": [56, 77, 97] },
  { "name": "Rolf", "marks": [45, 80] },
  { "name": "Anna", "marks": [87, 75, 100, 95, 98] },
  { "name": "Mary", "marks": [67, 70, 80] },
  { "name": "Stuart", "marks": [44, 55] },
  { "name": "Sophie", "marks": [86, 90, 100, 100] },
]

total = 0
count = 0

for student in students:
  total += sum(student['marks'])
  count += len(student['marks'])

print(total / count)

We could make it reusable it with a function:

def average(collection, key):
    total = 0
    count = 0

    for element in collection:
        total += sum(element[key])
        count += len(element[key])

    return total / count

This function takes has two parameters: collection and key.

It:

  1. Creates two variables to store a total sum of all grades and a total count of all grades.
  2. Then it loops over the collection variable, which could be any list or tuple.
  3. Then it tries to access the key key of each element in the collection. If key == 'marks', then it will try to access the 'marks' key of each element.
  4. It adds the sum and len to the respective variables
  5. Outside the loop it returns the average, which is total / count.

We could then use this function like so:

students = [
  { "name": "Jose", "marks": [56, 77, 97] },
  { "name": "Rolf", "marks": [45, 80] },
  { "name": "Anna", "marks": [87, 75, 100, 95, 98] },
  { "name": "Mary", "marks": [67, 70, 80] },
  { "name": "Stuart", "marks": [44, 55] },
  { "name": "Sophie", "marks": [86, 90, 100, 100] },
]

def average(collection, key):
    total = 0
    count = 0

    for element in collection:
        total += sum(element[key])
        count += len(element[key])

    return total / count

print(average(students, 'marks'))

I hope this makes some sense! Don't worry if it seems very complex. Try to play around with the code and change things; break things; and learn things by doing so.

Only by programming will you become proficient and master it!

I'll see you tomorrow.

Like what you see?

Join our e-mail list to receive new content as it's posted—once or twice a month!