In Python, modules are simply source files that are created with an intention of been imported and used somewhere else.  A package, on the other hand,  is a collection of modules that are grouped together under a common name.

While a module is an actual Python file containing Python code such as functions, variables and classes;  a package is basically a directory in the computer where related modules are put together. 

How to create a package

Well, as already said, a package is simply a directory containing python source files, it is that simple.  What separates a Python package from a regular directory is that a package must contain a special file called __init__.py .  This files serve two main purposes:

  1. The interpreter recognizes and interprets a directory with an __init__.py file as a package. This makes it possible to import the package and its modules, which would otherwise be impossible.
  2. The __init__.py file acts as the main entry point to a package. This file gets implicitly executed once the package is imported.

For demonstration, we will create a small package for performing some basic math calculations. Carry out the following actions from your working directory:

  • Create a new directory, you can just call  it app. This is where we will create the package.
  • Create a file called main.py inside the app directory. This is the script where we will invoke the package.
  • Create a new directory inside the myapp directory, you may call it simplemath.
  • Create an empty __init__.py file inside the simplemath directory.
  • In the same simplemath directory, create two Python files, basic.py and area.py

 You should have the following structure:

an image illustrating the structure of a Python package

That is it, you now have a package called simplemath in the app directory. Let us now add some code in the files inside the package.

Open the two files basic.py and area.py in your text editor or IDE, the two files should now contain the following python code.

basic.py

#basic.py

#functions for basic arithmetic
def add(a, b):
    print(f"{a} + {b} = {a + b}")

def diff(a, b):
    print(f"{a} - {b} = {a - b}")

def prod(a, b):
    print(f"{a} x {b} = {a * b}")

def div(a, b):
    print(f"{a} / {b} = {a / b}")

    

 area.py

#area.py

from math import pi

#functions for getting areas of basic shapes

def circle(r):
    '''calculate area of a circle given the radius'''
    area = pi * r * r 
    return area

def rectangle(w, l):
     '''area of a rectangle given width and length'''
     area = w * l
     return area

def square(a):
     '''area of a square of sides of length a'''
     area = a ** 2
     return area

def triangle(b, h):
     '''get area of a triangle of base b and height h'''
     area = 0.5 * b * h
     return area

Importing and using modules from the package

We will import and use the modules inside the simplemath package, from the main.py file. You should note that the file is inside the same directory with the package.

#main.py

#import modules from simplepath package
from simplemath import basic, area

#use functions from the basic module
basic.add(10, 20)
basic.prod(8, 9)

#use functions from the area module
print(area.circle(7))
print(area.triangle(6, 8))

10 + 20 = 30
8 x 9 = 72
153.93804002589985
24.0

There are various ways that we can use to import resources from our packages, the import statement from the above example shows one of them. They various approaches are as follows:

#ways of importing objects from a package

import simplemath.basic, simplemath.area #simplemath.basic.add(a, b)
from simplemath import basic, area # basic.add(a, b)
from simplemath.basic import add, prod #add(a, b)

The comments in the above example demonstrates how to use imported object depending on how the are imported.

Non-empty __init__.py File

In its basic form, the __init__.py file can just be empty but in some cases we may want it to hold some data associated with the package. You should be careful when using this file as the file gets executed each time we import any module from the package. 

One of the most important use of this file is when we want to define the modules that should be imported when we use the following statement.

from simplemath import *

When you run that statement, you would normally expect all the modules defined inside the package to be imported. However, that is not what happens, instead, only the objects that are defined inside the __init__.py module will be imported( In our case, None ). We can modify this behavior by defining a list, __all__, that contains all the module names associated with the package.This list should be defined in the __init__.py file.

__init__.py

#__init__.py

__any__ = ['basic', 'area']

All modules inside the __all__ list will now be imported when we run the import command with an asterisk.

#main.py

#import all modules from simplemath
from simplemath import *

#basic and area modules have been imported
basic.div(100, 20)
print(area.square(6))

100 / 20 = 5.0
36

Install a package systemwide

Once we have created the package and done the necessary testing, we may want to use the package from anywhere in the system rather than just from the directory where it is created. In this section, we will make our simplemath package global, so that we can use it from anywhere just like the builtin modules..

Python offers a very convenient way to perform such installations. The setuptools library defines the setup() functions which prepares a package for installation using pip.

You can run the following pip command to install the setuptools library, that is if it is not already installed.

pip install setuptools

Create a file called setup.py inside the simplemath directory with the following piece of code.

setup.py

#import the setup functions
from setuptools import setup

setup(name='simplemath',
version='1.0',
description='A package for performing simple math',
url='#',
author='auth',
author_email='author@email.com',
license='MIT',
packages=['simplemath'],
zip_safe=False)

Then run the pip install command from the app directory.

pip install simplemath

Collecting simplemath
  Downloading simplemath-1.0-py2.py3-none-any.whl (2.1 kB)
Installing collected packages: simplemath
Successfully installed simplemath-1.0

You can now use  the simplemath package system-wide just like you would with the builtin modules.