DEV Community

Cover image for Writing Reusable code in Python
Sharon-nyabuto
Sharon-nyabuto

Posted on

Writing Reusable code in Python

Understanding Functions

Previous articles in this series have guided us on how to make decisions, repeat tasks, and solve increasingly complex problems using Python.
As our programs grow, another challenge begins to emerge; repeating codes we need to use more than once.

Say you've written a program that checks a dataset for missing values. Later on, you need to perform the same check on a different dataset. Do you copy and paste the same code, or is there a better way?
Fortunately, Python allows us to group reusable code into a function, making it easy to use the same logic whenever we need it, entirely avoiding the repetition.

What is a Function?

A function is a reusable block of code that performs a specific task.
Functions allow us to package reusable code into a named block so we can call it whenever we need it, instead of writing the same logic repeatedly.
Functions don't just save typing, they make code reusable.

Defining your first function

Consider a task on analyzing several household survey datasets collected over different years. Before analyzing each one, you want Python to display the same message indicating that the analysis has started.

Without functions, you would need to write the same line of code every time.

print("Analyzing household survey dataset...")
print("Analyzing household survey dataset...")
print("Analyzing household survey dataset...")
Enter fullscreen mode Exit fullscreen mode

While this works, repeating the same code easily becomes difficult to maintain. If you later decide to change the message, you would have to edit it everywhere it appears.

Instead, Python allows us to define a function once and call it whenever we need it.

def analyse_dataset():
    print("Analysing household survey dataset...")
Enter fullscreen mode Exit fullscreen mode

Let's break it down:

  • def Is the keyword that tells Python that you are defining a new function.
  • analyse_dataset is the function's name. It should be a descriptive name, i.e. it should explicitly describe what the function does.
  • () is where any information the function needs (known as parameters) will go. For now, the parentheses are empty because our function doesn't require any input.
  • : marks the beginning of the function body.
  • The indented code underneath is the set of instructions Python executes each time the function is called.

Notice that nothing happens yet. This is because defining a function only tells Python that it exists. The code inside the function will not run until we explicitly call it.

Calling a function

Once a function has been defined, you can execute it simply by writing its name followed by parentheses. This is what is known as calling the function

In the case of our example above, we simply write the name of the function whenever we need it, as many times as we would need it.

analyse_dataset()
analyse_dataset()
Enter fullscreen mode Exit fullscreen mode

the output:

Analysing household survey dataset...
Analysing household survey dataset...
Enter fullscreen mode Exit fullscreen mode

Let's see how we can have a function performing a specific task.

Scenario: You've received a household survey dataset. Before analyzing it, you want to know how many records are complete.

# The dataset
household_survey = [
    ["HH001", 25000, 4], ["HH002", None, 3],
    ["HH003", 18000, None], ["HH004", 32000, 5],
    ["HH005", None, 6]]  

# The function
def count_complete_records():
    complete = 0

    for row in household_survey:
        if None not in row:
            complete += 1
    print(f"Complete records: {complete}")

# Calling the function
count_complete_records()
Enter fullscreen mode Exit fullscreen mode

What happens Step by Step:

  1. Python defines the function count_complete_records().
  2. When the function is called, it loops through the dataset.
  3. Each row is checked to see if it contains any missing values (None).
  4. If the row is complete, the counter increases by one.
  5. After checking every record, Python prints the total number of complete records, i.e.
Complete records: 2
Enter fullscreen mode Exit fullscreen mode

This function works well, but it has one limitation. It is written specifically for the household_survey dataset because the dataset is hardcoded inside the function.
If we needed to count complete records in a different survey, we would either have to edit the function or create another one. When working with multiple datasets, this becomes a little inefficient.
Fortunately, it is possible to write one function that works with different datasets.

Parameters

Rather than storing the dataset inside the function (as we did in the example above), Python allows us to pass the dataset into the function whenever it is called. We do this using parameters.

A parameter is a variable listed inside a function's parentheses. It acts as a placeholder that receives the information passed to the function when it is called.

def count_complete_records(dataset):
    complete = 0

    for row in dataset:
        if None not in row:
            complete += 1
    print(f"Complete records: {complete}")
Enter fullscreen mode Exit fullscreen mode

Notice the difference between this function and the previous one. This time, the function includes a parameter, dataset.

In this case, dataset acts as a placeholder for the dataset we want the function to work with. Because the dataset is no longer hardcoded into the function, the same code can be used with different datasets.

But where does the parameter get its value?

It receives its value when the function is called. For example:

count_complete_records(household_survey)
Enter fullscreen mode Exit fullscreen mode

Notice another difference here. This time, the parentheses contain the name of the dataset we want to analyse. This is known as an argument.

When the function is called, Python takes the value of household_survey and passes it to the parameter dataset.
From that point onwards, every time the function refers to dataset, it is working with household_survey.

Parameter             Argument

dataset   <─────── household_survey
Enter fullscreen mode Exit fullscreen mode

In simple terms, the parameter is the placeholder inside the function, while the argument is the actual value you provide when calling the function.

Now if we needed to count the number of complete records in the economic impact survey below;

economic_impact_survey = [
    ["B001", None, "Farmer"],
    ["B002", 150000, "Trader"],
    ["B003", None, "Fisher"],
    ["B004", 12000, "Farmer"],
    ["B005", 15000, "Farmer"], 
    ["B006", None, None]
]
Enter fullscreen mode Exit fullscreen mode

we would not need to modify or define the function all over again, but just pass the argument(name of the dataset) when calling the function;

count_complete_records(economic_impact_survey)
Enter fullscreen mode Exit fullscreen mode

The output:

Complete records: 3
Enter fullscreen mode Exit fullscreen mode

Because the function uses a parameter, it can work with any dataset that follows the expected structure.

An important point to remember is that simply existing does not make functions reusable. It is the presence of parameters that allows them to work with different inputs.

Returning Values

In the examples above, we have been displaying the results of our functions immediately using print. This is helpful for when we want to see the result.
In some situations, we do not want to see the result, but want to use the result elsewhere in the program.

Suppose we wanted to compare the number of complete records in two different datasets. Printing the result alone wouldn't allow us to perform that comparison. We would need a way for the function to send the result back to the rest of the program.

The return statement sends a value back to the place where the function was called.
Think of print() as showing the result to the user, while return gives the result back to the program so it can continue working with it.

Let's modify our function;

def count_complete_records(dataset):
    complete = 0

    for row in dataset:
        if None not in row:
            complete += 1

    return complete
Enter fullscreen mode Exit fullscreen mode

Notice that we've replaced:

    print(f"Complete records: {complete}")
Enter fullscreen mode Exit fullscreen mode

with:

    return complete
Enter fullscreen mode Exit fullscreen mode

Now, instead of displaying the result immediately, the function hands the value back to the program. These values can then be stored in variables;

household_complete = count_complete_records(household_survey)
economic_complete = count_complete_records(economic_impact_survey)
Enter fullscreen mode Exit fullscreen mode

The variables now contain the number of complete records for each dataset, and since the values have been stored, they can be printed, compared or used in other calculations.

For example, we can compare the number of complete records in the two datasets as follows:

if household_complete > economic_complete:
    print("The household survey has more complete records.")
else:
    print("The economic impact survey has more complete records.")
Enter fullscreen mode Exit fullscreen mode

The output:

The economic impact survey has more complete records.
Enter fullscreen mode Exit fullscreen mode

Using the return statement makes functions far more flexible and reusable, because they can be stored in a variable and be used later.

Conclusion

In this article, we have seen how functions enable us to write reusable code, by defining them once and calling them whenever we need them. By using parameters, the same function can even work with different datasets, making our programs more flexible and easier to maintain.

This brings us to the end of our introduction to Python series. Throughout this series, we have built the skills needed to write clear, reusable Python programs, from making decisions and repeating tasks to organizing code with functions.

Continue practising beyond the examples we've explored, experiment with your own ideas, and challenge yourself with new problems. The confidence you build comes not from reading code, but from writing it.

In future articles, we will shift our focus from learning Python itself to applying these skills to data analysis, showing how they come together to solve practical problems.

Top comments (0)