Building a Python project with Modules and packages

Building a Python project with Modules and packages

This article explores Python modules and Python packages, two mechanisms that facilitate modular programming.

Modular programming refers to the process of breaking a large, unwieldy programming task into separate, smaller, more manageable subtasks or modules. Individual modules can then be cobbled together like building blocks to create a larger application. In this article I will show you the rationale behind a Python module, the differences with a package and how the two things interact together.

Python modules vs. Python packages

A module is a Python file which contains code, saved with the .py extension. Every time you write a function, a class or a statement and save it to a .py file you are actually creating a new module. A module can be executed by the Python interpreter directly, e.g. python script.py and thus called main module, or imported by other modules. Modules are a way to lay out your program in different files for easier maintenance.

When you have many modules in your project it's good practice to organize them into folders. For example, say I'm working on a very primitive game in Python called Fancy Game: I would like to structure the directory as follows:

fancy_game/
    models/
        player.py
        monster.py
    audio/
        mixer.py
        effects.py
        player.py
    graphics/
        renderer.py
        screen.py
    common/
        constants.py
    main.py

A package is simply a collection of Python modules organized into folders. In my Fancy Game the packages could be: models, audio, graphics and common. The fancy_game folder is not a package itself, because it is intended to be run directly by Python (i.e. python main.py). Sometimes you want to create a library instead to be imported in other Python programs, so the entire root folder would become a package too (made of many sub-packages).

Having a project or a library organized into packages is a good thing: a) your source code is even more modularized and b) packages provide protection against name clashes with other modules. We'll see why in a minute.


You may also like: How to create the Structure of a Python Project


Turn a folder into a Python package

Python has to be instructed about which directory should become a package. To do this, simply add an empty file called __init__.py inside each desired folder. This is a special file used to mark directories on disk as Python package directories. So, my Fancy Game folder structure would be:

fancy_game/
    models/
        __init__.py        <--- new __init__.py file added
        player.py
        monster.py
    audio/
        __init__.py        <--- new __init__.py file added
        mixer.py
        effects.py
        player.py
    graphics/
        __init__.py        <--- new __init__.py file added
        renderer.py
        screen.py
    common/
        __init__.py        <--- new __init__.py file added
        constants.py
    main.py

Notice how there is no init.py in the root folder: this is because my game (i.e. main.py) is intended to be run directly from the Python interpreter. In case of a library, simply add the special file into the root directory as well.

Importing modules from packages

Now that the whole structure has been set up, the code inside main.py needs to import some modules from the various packages in order to make the game work. To import a module from a package you have to follow the dotted module name syntax. For example, in the main module I want to import the player module from the audio package:

# main.py
import audio.player

More generally, the rule is import [package].[module]. This also works in case you have nested packages: import [package1].[package2].[module] and so on.

Once imported, the module must be referenced with its full name. So if I want to use the function play_sound() from within the audio.player module I have to call it as audio.player.play_sound(). As mentioned above, this is a good way to avoid name clashes across different modules: I can easily import the module model.player without messing up with its homonym audio.player:

# main.py
import audio.player
import model.player

# Two modules with the same name: no problem
audio.player.play_sound()
model.player.run()

Importing modules from above

Sometimes a deep-buried module needs to import stuff from the upper level. For example, the audio.player module might need something inside common.constants. There are two ways of doing it:

absolute import — import the module as if the importer is located in the root directory. Python is able to figure out the right path. For example, in audio.player just do import common.constants. This is my favorite option; relative import — use the formula from [module] import [name] with dots to indicate the current and parent packages involved in the import. For example, in audio.player you can call from .. import common.constants. One dot means the current package, two dots is up one level, three dots is up two levels and so on. I'm not a huge fan of this one, as relative imports break easily when you move modules around.

Shorten module names

Using long names such as models.monster.Skeleton is quite inconvenient. You can shorten a module name while importing it with an alias, for example:

# main.py
import models.monster as monster

Now models.monster is available as monster. Just keep in mind that this way might lead to name clashes across modules.

Learn More

Python 3 Tutorial for Beginners - Modules & Packages

python

What is Geek Coin

What is GeekCash, Geek Token

Best Visual Studio Code Themes of 2021

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

top 30 Python Tips and Tricks for Beginners

In this post, we'll learn top 30 Python Tips and Tricks for Beginners

Lambda, Map, Filter functions in python

You can learn how to use Lambda,Map,Filter function in python with Advance code examples. Please read this article

Python Tricks Every Developer Should Know

In this tutorial, you’re going to learn a variety of Python tricks that you can use to write your Python code in a more readable and efficient way like a pro.

How to Remove all Duplicate Files on your Drive via Python

Today you're going to learn how to use Python programming in a way that can ultimately save a lot of space on your drive by removing all the duplicates. We gonna use Python OS remove( ) method to remove the duplicates on our drive. Well, that's simple you just call remove ( ) with a parameter of the name of the file you wanna remove done.

Basic Data Types in Python | Python Web Development For Beginners

In the programming world, Data types play an important role. Each Variable is stored in different data types and responsible for various functions. Python had two different objects, and They are mutable and immutable objects.