Python Single Responsibility Principle

You’ve probably heard about programming principles. A piece of advice that always gets thrown around is “have the smallest classes/functions/modules possible”. What does that mean though? How do you make a function as small as possible? The single responsibility principle. This programming principle dictates how small a function could possibly be.

In this post, we’ll cover:

  • The Single Responsibility Principle
  • SRP Example with Python Functions
    • Generating Data Points
    • Plotting Generated Data Points
    • Putting them Together
  • A Summary of the Single Responsibility Principle Example

The Single Responsibility Principle

The Single Responsibility Principle (SRP) applies to modules, classes, and functions. In this example, we’ll be demonstrating the SRP with functions. It states that each function should have responsibility over a single part of a program’s functionality and encapsulate that part. 

Encapsulation refers to the bundling of data with the methods that touch that data. It also refers to the idea of restricting direct access to the components of an object or function. It can be thought of like the way we use APIs. When encapsulation is done correctly, we can think of each function to be a black box that returns a specified return value given a set of parameters.

The Single Responsibility Principle is the reason we often see programs divided into many nested directory structures. For example, if we’re working with a blog website, we may see folders like utils, users, and posts. Under each of those folders we’ll see files for specific functionality. For example, under users we may see separate files for logging in, registering, logging out, deleting users, and updating users.

SRP Example with Python Functions

In this post, we’ll cover a small example of SRP of functions with Python. We’ll create two functions that each encapsulate one action, and then one orchestrator function. Before we start, you’ll need to install the matplotlib library, which you can do so by using the line below in the terminal:

pip install matplotlib

In this example, we will generate a set of data points corresponding to the line y=2x for the x values from 0 to 1. Then, we will plot these data points. To show SRP, we’ll create one function which takes no parameters to generate the data points and one function which takes two parameters, lists x and y, and plots the data points.

When applying SRP on classes and modules, we typically split each class or module into its own file or directory. However, when working with functions we don’t need to do that. In this case, we will put the functions in the same file. We’ll open up our file as we always do with our imports. For this example, we’ll need to import matplotlib and random.

import matplotlib.pyplot as plt
import random

Generating Data Points

The first function we’ll make for this example is a function that generates data points. This function will take no parameters. We’ll start off by creating a list of 25 uniformly distributed x values from the range 0 to 1. Then we’ll sort those x values and create a list of y values equivalent to 2x for each value in the list. Finally, we’ll return both lists.

# function 1 - generate dataset
def gen():
    x = [random.uniform(0, 1) for _ in range(25)]
    x.sort()
    y = [2*_x for _x in x]
    return x, y

Plotting Generated Data Points

Our second function will plot two lists of data points. It will take two parameters, the list of x values and the list of y values. First, we’ll call the matplotlib.pyplot or plt class that we imported to plot the x and y values. Then, we will add a title to the plot. Finally, we’ll call the show() function to display the plot.

# function 2 - plot generated dataset
def plot(x: list, y: list):
    plt.plot(x, y)
    plt.title("plotting a generated dataset")
    plt.show()

Putting them Together

Finally, we have our two functions, it’s time to put them together. We’ll create an orchestrate function which takes no parameters. This function will simply call the gen() function and assign its outputs to two variables, x, and y, and then call the plot function to plot x and y

Note that this function is actually not necessary, if you wanted to, you could simply put the two lines in this function directly in the script. This function is only here to illustrate an example of best practices of encapsulation.

# function 3 - tie them together
def orchestrate():
    x, y = gen()
    plot(x, y)
   
orchestrate()

To call the function itself, we simply put a call to orchestrate() in our script. When we run our script, we should end up with a plot of the line y=2x as shown below.

Single Responsibility Principle Summary

In this post we learned about the Single Responsibility Principle and how it affects program structures. We then went over an example of SRP applied to functions in Python. In our example, we created a function that creates a dataset and graphs it. We applied SRP by splitting the functions into one that creates the dataset, one that graphs it, and one that puts them together.

I run this site to help you and others like you find cool projects and practice software skills. If this is helpful for you and you enjoy your ad free site, please help fund this site by donating below! If you can’t donate right now, please think of us next time.

Yujian Tang

Leave a Reply

%d bloggers like this: