7th Nov 2022 13 minutes read 10 Useful Tips for Writing Python Scripts Xavier Rigoulet python script Would you like some helpful tips for Python scripts? Read on to get some advice from a pro! In this article, I will give you some Python tips and tricks alongside script examples to help you make the best out of Python. First, let's define what a Python script is. A Python script is a set of instructions written in Python to ask the computer to perform some tasks. Before we get started with the Python tips, make sure that you understand Python data structures first. If you’re not familiar with them, consider taking our Python Data Structures course. Its 118 interactive exercises will give you the opportunity to work with lists, nested lists, sets, tuples, and dictionaries. For this article, we will start with a simple use case and improve our script as we implement the different tips for writing useful Python scripts. 10 Useful Tips for Better Python Scripts For a starter, we will write a script that reads an RGB image and converts it to grayscale, a basic pre-processing step in computer vision. We’ll use OpenCV for this step. If you do not have OpenCV installed, you can do it easily with pip: pip install opencv-python For this example, I have downloaded 50 images of Formula One cars saved in data/formula_one with files from 000000.jpg to 000049.jpg. First, let's create a Python file called gray.py and execute it in the terminal. It will read the images, convert them to grayscale and display them on our screen. import cv2 import glob image_files = sorted(glob.glob("./data/formula_one/*.jpg")) for i in image_files: img = cv2.imread(i) gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray_img_small = cv2.resize(gray_img, (960, 540)) cv2.imshow('Grayscale Image', gray_img_small) cv2.waitKey(0) cv2.destroyAllWindows() Below is an example of the results: Now that we have something running, let's see how we can improve this script with the first Python script tip. 1. Emphasize Python Code Readability My first tip is not to write scripts for yourself, even if you are the only one using them. Instead, think about your future self – or, if you write Python code for someone else, about the person who will maintain the code after you. In other words, your code must be well-commented, readable, and understandable by anyone who’ll look at your Python script. If you decide to over-engineer your code and make it highly optimized at the expense of readability, you must be thorough in your comments. I haven't put any comments in my previous example, so this can be the first step to improving our Python script. Let's use comments to explain what our code does: import cv2 import glob # Load the images in ascending order image_files = sorted(glob.glob("./data/formula_one/*.jpg")) # Loop through the files display them as grayscale for i in image_files: img = cv2.imread(i) # Read the image gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Convert the image to grayscale gray_img_small = cv2.resize(gray_img, (960, 540)) # Resize the image for visualization purpose cv2.imshow('Grayscale Image', gray_img_small) # Display the gray image in a window called 'Grayscale Image' cv2.waitKey(0) # Press any key to close the window cv2.destroyAllWindows() # Close all the open windows Now our code is much clearer. Later on, these comments will help you remember your thought process when writing the code. However, our comments might be a bit obvious, as this article is a tutorial on Python tips and tricks. In this context, comments often explain the “what” of the code; instead, it’s often a good practice to write the “why” of this code snippet. For example, I could’ve written the comments like this: import cv2 import glob # Sorting the images in order is essential when the images are recorded in sequences (i.e., videos, sensor capture with timestamps) # This is particularly important if the images are video frames, where the order matters. image_files = sorted(glob.glob("./data/formula_one/*.jpg")) # Converting to grayscale normalizes images and makes image processing faster. It helps machine learning models when color is not an important feature. for i in image_files: img = cv2.imread(i) gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray_img_small = cv2.resize(gray_img, (960, 540)) cv2.imshow('Grayscale Image', gray_img_small) cv2.waitKey(0) cv2.destroyAllWindows() 2. Write Reusable Python Functions If you can make your code fully reusable with the help of functions, you will save yourself a lot of pain. So, instead of writing the instructions directly in your file, try to wrap them up within functions. This will force you to generalize your code and make it more reusable for future scripts. Let's write a function to take our image file as an argument and return the non-resized gray image. We’ll put the function at the top of the script, just after the imports: import cv2 import glob # Color to Gray Function def color2gray(filename): img = cv2.imread(filename) # Read the image gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Convert the image to grayscale gray_img_small = cv2.resize(gray_img, (960, 540)) # Resize the image for visualization purposes cv2.imshow('Grayscale Image', gray_img_small) # Display the gray image in a window called 'Grayscale Image' cv2.waitKey(0) # Press any key to close the window return gray_img # Load the images in ascending order image_files = sorted(glob.glob("./data/formula_one/*.jpg")) # Loop through the files and display the images as grayscale for i in image_files: color2gray(i) cv2.destroyAllWindows() # Close all the open windows 3. Write Your Own Python Package My next tip is a follow-up for the previous one. Now that you’ve already started to make your code reusable by adding functions, you can store those functions in a Python file. You can import this file like any library and pull your functions whenever you need them. The next step is to organize your code in classes. This can also allow you to use the dir() method to access the list of functions in your file. Let's put our previous function in a new Python file called utils.py and import it like any Python package. Remember that your utils.py file needs to be in the same directory. import cv2 # Color to Gray Function def color2gray(filename): img = cv2.imread(filename) # Read the image gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Convert the image to grayscale gray_img_small = cv2.resize(gray_img, (960, 540)) # Resize the image for visualization purposes cv2.imshow('Grayscale Image', gray_img_small) # Display the gray image in a window called 'Grayscale Image' cv2.waitKey(0) # Press any key to close the window return gray_img And the updated gray.py file: import cv2 import glob import utils # Load the images in ascending order image_files = sorted(glob.glob("./data/formula_one/*.jpg")) # Loop through the files display them as grayscale for i in image_files: utils.color2gray(i) cv2.destroyAllWindows() # Close all the open windows If, for some reason, your utils.py file is in another directory, you can import it into your gray.py file: import cv2 import glob import sys sys.path.append("your-path-to-utils") import utils # Load the images in ascending order image_files = sorted(glob.glob("./data/formula_one/*.jpg")) # Loop through the files display them as grayscale for i in image_files: utils.color2gray(i) cv2.destroyAllWindows() # Close all the open windows There's more to know about Python packages, but this should get you started. Readability is one of the advantages of storing your functions in a dedicated Python file, but it also makes your code easier to maintain. You can access the list of your functions with dir(). import utils print(dir(utils)) We get the following output: ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'color2gray', 'cv2'] You can see color2gray, the function we defined before. But that's not all. Next, let's move on to one of my best Python tips and tricks as we look at the argparse module. 4. Include Command-Line Arguments Want to make your script reusable? Generalize it! What a hassle to have to dig into your previous Python script to edit it for your current use case! So, save yourself the trouble and use argparse. You will thank yourself later! Argparse is a powerful Python library. I encourage you to read my guide to the Python argparse module to learn more about it. In the meantime, let's update our code to include it and be able to execute our Python script with command-line arguments. import cv2 import glob import utils import argparse as ap # Define an argument parser object parser = ap.ArgumentParser() # Define the arguments to add parser.add_argument("-d", "--directory", type=str, required=True, help="Directory of files to load") parser.add_argument("-e", "--ext", type=str, default=".jpg", help="Define file extension") args = parser.parse_args() # Load the images in ascending order image_files = sorted(glob.glob(args.directory+"*"+args.ext)) # Loop through the files display them as grayscale for i in image_files: utils.color2gray(i) cv2.destroyAllWindows() # Close all the open windows We can run our script as follows: python gray.py --directory ./data/formula_one/ --ext .jpg Including argparse in your script makes it fully reusable. Using it, you can type the arguments you need to execute the scripts according to your needs without editing the code directly. 5. Use docstring Instead of Single-Line Comments Next, I recommend using docstring instead of single-line comments (i.e comments with #). There are two reasons for this. On the one hand, you can write multi-line comments effortlessly and correctly; on the other hand, the program user can have access to the comments by calling the help() function. Strings are an essential Python data structure. Feel free to check out our course on working with strings in Python if you want to learn more. Let's edit our utils.py file to include a docstring comment: import cv2 # Color to Gray Function def color2gray(filename): """ This function reads an image and converts it to grayscale. For visualization purposes, we resize the output as a 960x540 image. Press any key to close the window and continue. """ img = cv2.imread(filename) gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray_img_small = cv2.resize(gray_img, (960, 540)) cv2.imshow('Grayscale Image', gray_img_small) cv2.waitKey(0) return gray_img print(help(color2gray)) Then, we can run our utils.py in the terminal … python utils.py … and get the function documentation below: Help on function color2gray in module __main__: color2gray(filename) This function reads an image and converts it to grayscale. For visualization purposes, we resize the output as a 960x540 image. Once the image is displayed, press any key to close the window and continue. (END) 6. Use Version Control Have you had your laptop die in your hands because someone spilled a cup of water on it? Or have you lost all your files because you made a typo when running the Linux rm -rf command to delete a directory? Both have happened to me, so you don’t have to repeat my mistake! To avoid rewriting your scripts or taking your screwdriver to open your laptop and extract your hard drive, save yourself some trouble with version control. A few options are available, such as GitLab, GitHub, Beanstalk, and more. I personally use GitHub. Pushing your code regularly will ensure that you always have a project version available. It can be done in the blink of an eye: Go to your project directory and open your command-line terminal. Type $ git init Type $ git add your-project-filenames Type $ git commit Go to your GitHub account and create a new repository. In your command-line terminal, type $ git remote add origin git@github.com:your-username/your-repo Type $ git push That’s it! You’re all set. If you want to learn more about how to get started using GitHub, now is a good time to learn! 7. Serialize Your Python Variables for Reuse Object serialization can also be handy. Let's say one of your functions takes a long time to run and you will have to reuse the same output in multiple files, either for research purposes (like doing multiple experiments) or for some other use case. Instead of running your code multiple times, you can serialize the output by saving it as a pickle file and reloading it in your next script. In our previous example, our function returned the grayscale image as a NumPy array; our script runs 50 images. Maybe you have a script doing the same things for thousands of images and you need those NumPy arrays for another purpose. We can save these data structures for future reuse to avoid re-running the code. Let's import pickle and update our script: import cv2 import glob import utils import argparse as ap import pickle as pkl # Define an argument parser object parser = ap.ArgumentParser() # Define the arguments to add parser.add_argument("-d", "--directory", type=str, required=True, help="Directory of files to load") parser.add_argument("-e", "--ext", type=str, default=".jpg", help="Define file extension") args = parser.parse_args() # Load the images in ascending order image_files = sorted(glob.glob(args.directory+"*"+args.ext)) # Create an empty list gray_arr = [] # Loop through the files display them as grayscale for i in image_files: arr = utils.color2gray(i) gray_arr.append(arr) # Append the gray arrays to a list cv2.destroyAllWindows() # Close all the open windows # Save the gray images as a list of Numpy arrays in a pickle file. with open("gray_arr.pkl", "wb") as f: pkl.dump(gray_arr, f) Now, you can directly load the gray_arr.pkl file and retrieve the saved data structure. This can save you time by avoiding re-running the script multiple times to retrieve the results. It can also be a way to free up memory. Instead of storing your values in a list, you can save them as a pickle file and delete the variable to reduce the load on your memory. 8. Use Optimized Python Libraries My next essential tip comes directly from the previous example where we saved a bunch of images as NumPy arrays – a Python library written in C. C is a much faster language than Python. But Python, despite being slower, is straightforward to use and tends to make development faster, which explains its popularity and versatility. By using libraries written in C, you make your Python code much easier and faster. If your hardware supports Cuda, you can also use CuPy, a version of NumPy optimized for GPUs, making your code faster still. These libraries are also very convenient and allow you to make complex mathematical operations with one function call. 9. Write Pythonic Code My next tip is to use Python one-liners to make your code more concise and elegant. Our previous code stores the output of the color2gray function in a traditional list: # Create an empty list gray_arr = [] # Loop through the files display them as grayscale for i in image_files: arr = utils.color2gray(i) gray_arr.append(arr) However, we can rewrite this in Pythonic fashion as a one-liner: gray_arr = [utils.color2gray(i) for i in image_files] Now our code is more concise and more elegant – and, above all, more Pythonic! 10. Take Care of Possible Errors When your script works properly without throwing any errors, that's great. But it’s rarely the case. And sometimes errors are part of the process and should not stop your script. For example, you may want to scrape some images, but the request throws an exception error and cannot return any image. Then your script stops without executing the instructions you asked it to do. Thus, the way you end your Python script is important. To prevent your script from stopping, you can make use of try-except; in this case, exception handling will only skip the file and keep your script from stopping. More Helpful Tips for Writing Python Scripts In this article, we learned some useful tips for writing Python scripts. There is much more to say, but we have already covered enough ground to get you started. If you want to explore further, feel free to read some of my other things that can help you write better Python code. And if you haven't yet, why not join our Python programming track? Tags: python script