Organize Your Code

Christophe Leborgne
The Python Coder
Published in
9 min readMay 16, 2021

Of functions, modules and packages

Photo by Kelly Sikkema on Unsplash

Now that you have learnt the very basics of coding from the previous article, we should move forward and learn how to write bigger programs.

So far, the bigger script we wrote was about 5 lines long and, you guess it, real programs are way bigger. And also, we have learnt the fundamentals but we should build some code and reuse it to build always more sophisticated programs. This is what this article is all about.

Imagine we need to write down a program that takes a list of strings as input and prints all the strings of the list forcing the first letter of each word to be capital and the rest of the word being lower-case. Think of how you would do before reading the below code …

words = ['Hello', 'my', 'name', 'is', 'JOHN']
for word in words:
if word:
capped_word = word[0].upper()
if len(word) > 1:
for letter in word[1:]:
capped_word += letter.lower()
print(capped_word)

Same as always, let’s read it step by step and understand what this code does.

First line is quite simple, we just declare the list of strings and call it ‘words’. Easy

On the second line, we loop through the list of all the words and store the word being processed in the variable ‘word’. Should sound familiar now.

Third line is a new thing. if word: I thought if statement had to be followed by a conditional? And word is not a boolean but a string. Well you are right. But in python, strings that are undefined, equal to the specific empty value of None or just empty (the empty string is two quotes with nothing in it) are False. All the rest is True. So when we write if word:, we check that word contains something! It might seem weird at the beginning, but that’s the way we do it.

On the fourth line, we create a new variable called capped_word and store the first letter of word (word[0] Just like with lists, we can access a specific character of a string by using square brackets) and we capitalize it with the .upper() function.

Then we check if there is still something later, using the len() instruction that gives the length of a string or a list and loop through the rest of the letters, using the word[1:] slice that we have seen in the previous article.

We append the rest of the letters and force them to be lower-case using the .lower() function. Note the strange notation of capped_word += which is shortcut for capped_word = capped_word +

Note also the indentation before the print(capped_word). Try to push it to the right or to the left and see how the result differs!

Are you OK? The logic behind this exercise is getting a bit more difficult, no? Imagine you write this code and let it set. And 6 months after, you need to reuse it and edit it a bit. Do you think what the code does would be obvious to you, just reading it? Not sure.

Let’s see how we can improve its readability.

Comments

In python, we can comment code using the # sign. Every thing that appears after it is just ignored by the interpreter (the interpreter being the program that actually runs the code). So we can rewrite the code we just wrote and add some comments like this

words = ['Hello', 'my', 'name', 'is', 'JOHN']
for word in words: # Loop through all the words of the list
if word: # Make sure we are not working an empty string
capped_word = word[0].upper() # Capitalize the first letter
if len(word) > 1: # if there is still something to loop thru
for letter in word[1:]: # loop thru the rest of the word
capped_word += letter.lower() # append the rest of the word lowercased
print(capped_word) # display the word with only the first letter capitalized

Whah! If you do that you will understand what you wrote even years after! But is this really worth? Would it be better to write code that is self-explanatory and limit the comments the minimum? Well, this is an eternal debate in the developers community. I personally prefer to write simple scenario and use very little comments. Some developers prefer writing comments. This is your personal choice, there is no official rule. How then could we rewrite this piece of code to make it easier to read and understand in a few months?

Functions

So far, I have used the word function a few times but never really explained it. I said that len() is a function that gives the length of a list or a string. We also saw the function print() and said it was an instruction to display stuff.

A function is a piece of code that takes some input and does something with it and return a result. A function may be given by the language itself, like print() or len(), we say it is built-in or created by the python coder.

If we want to recode our example using a function, this might look like this

def capitalize(str):
capped_str = ''
if str:
capped_str = str[0].upper()
if len(str) > 1:
for letter in str[1:]:
capped_str += letter.lower()
return capped_str
words = ['Hello', 'my', 'name', 'is', 'JOHN']for word in words:
if word:
capped_word = capitalize(word)
print(capped_word)

Let’s read it together.

In the first part, we create a new function called capitalize using the special python instruction def. It takes one parameter called str. Note the colon at the end of the function definition. And its content is the same as the code we had before. The only difference is the last line with the reserved word return. A function, though it’s not mandatory, often returns an output. Here the string called capped_str.

Then the second part is just the declaration of the list of words. And the last part is the main part of our program. It loops through the list, and, if the word is not empty, calls the capitalize function and stores the result in capped_word to display at the next line.

Isn’t that clearer? Another big advantage of functions is that you write a function once and you can reuse it several times in the same program. As a general rule, every time you feel like you have to copy and paste some code, there is probably a function to create. This is the rule “Don’t Repeat Yourself” as we call it. It’s a very important principle in coding, so important it has its own wikipedia page!

If for some reason, you want to change the logic behind the capitalization content, you just have to change your function. If you copied and pasted the code several times, you have to edit your code in several places with the risk of missing a bit and create a bug!

Note that if you don’t need any incoming parameter for your function, you still need to add a pair of round brackets () at the end of the function name. Don’t forget them, or you will get an error message!

Modules

As time goes, your code is going to grow bigger and bigger. And will need to split it into different files. In python, files are called modules. If you remember the very first post of this series, we then created a file called “helloworld.py”. And we were running it from the command line using the following command

$ python helloworld.py

In this example, helloworld.py is a module.

Modules are a good way to store things that are alike and we will see just after how to use the content, say a function defined in a module from another module. We can imagine creating a module called “string_functions.py” where we would put all the functions we created to handle strings. And in the main.py module, we have the main scenario of our program and the functions are outsourced in the external modules. Are you convinced or creating big things is still out of your imagination? We will see this soon. For the moment, let us just see how we can import the content of a module into another one.

The import statement

if you want to import some functions from one module to another, you have to import the source module from the target one using the import statement.

Copy the content of our capitalize function that we created before and save it in a file called string_functions.py. The file should look like this

def capitalize(str):
capped_str = ''
if str:
capped_str = str[0].upper()
if len(str) > 1:
for letter in str[1:]:
capped_str += letter.lower()
return capped_str

Then create a file called main.py and type this in it

from string_functions import capitalizewords = ['Hello', 'my', 'name', 'is', 'JOHN']for word in words:
if word:
capped_word = capitalize(word)
print(capped_word)

Make sure string_functions.py and main.py are in the same directory. And run main.py using the now well known procedure

$ python main.py

Still works? Great! Now let us talk about something close to modules but a bit bigger … packages.

Packages

Packages are similar to modules as they provides some functions to your code but they provide even more functionalities as they are a full directory of modules.

It is possible to create our own packages and we will see this later when talking about Flask but for the moment we are going to focus on packages that are available through the Python Standard Library whose full documentation is here.

It is a massive amount of functions (and classes we will discover just after) that were coded by professional developers and that are available to you for free. We won’t browse it all right now and I suggest you click on the link I gave you before. But let us take a few examples.

Imagine you want to open a file and read its content. This is something that we do very often. But there is a full collection of files to read, so the files are not located in the same directory as your program but in a sub-directory called ‘reports’ to keep things tidy.

As you know, on Windows machines, directories are separated by backslashes \ and in the Unix world (that includes Mac OS X) the separators are forward slashes /. If we want to send the program we are proud of to different users, do we have to code the two possibilities? Well no, there is a solution in the os package. Let us see this

import osf = open(os.path.join(os.getcwd(), 'reports', 'report-2020-04-22.txt'), 'r')
lines = f.readlines()
for line in lines:
print(line)

If you want to do the same thing as I did, copy this code a module, say open.py, and create a folder ‘reports’ next to it and create a file called ‘report-2020–04–22.txt’ in this folder. Then put some dummy content in the text file and save. Then run your python code and the content of the report file should print.

How does it work?

In the first line, we import the os package from the library. Note that unlike what we did to import functions from a module, we are not compelled to name the functions that we want to import using the from somewhere import this, that. We now import the whole package using simply import this.

Then the second is the big one. We are using three functions that are nested one into another. Let us just unstack all this from the inside out. The innermost function is os.getcwd() and it is fully described here. It actually just returns the current working directory (thus cwd) as a string. Then we have the operation system-agnostic os.path.join() function that joins all the parameters it is given (here we have three of them) and we don’t have to worry about using forward or backslashes, it will use the appropriate one at execution.

And the outermost function is not imported from os, it is built-in function of python called open(). This function takes two parameters. The name of a file to open and the opening mode. This mode is a single-character string with values ‘a’ for append, ‘r’ for read or ‘w’ for write. Here we use ‘r’ to read the content of the file. And the open() function returns a file handler that we call f.

Then we use the readlines() function of the file handler to get a list of strings, each item of the list being a line in the file. And we print it, just to prove it worked!

I suggest you take a look at the available packages from the link I gave you. Maybe you can look at time or sys to start.

--

--

The Python Coder
The Python Coder

Published in The Python Coder

Some valuable content for those of you who want to learn python or already have some years of python under your belt

Christophe Leborgne
Christophe Leborgne

Written by Christophe Leborgne

I am now a devops engineer. I have been coding for decades and recently moved to a more “ops” position. Willing to share a bit of my experience here

No responses yet