Table of Contents
In this tutorial, we are going to look into Python Packages, sub-packages and modules with the help of best examples. In Python, packages are generally represented by directories in the File System while modules are represented by single file. Python basic tool to organize code is through modules. A module typically corresponds to a source file. We load modules into the program by using import keyword. When we import a module, it is represented by a type called module. We can interact with it like any other objects. More about Python Modules.
Python: Packages, Sub-Packages and Modules with Best Examples
Also Read: Python: Introduction to Strings and Slices with Examples
A package in python is just a special type of module. The defining characteristic of a package is that it can contain other modules including other packages. So packages are a way to define hierarchy of modules in Python. To see an example, open your Python Interpreter and import urlib and urllib.requests and then check its type. You will see that both of them are module as shown below.
root@cyberithub:~# python3 Python 3.8.10 (default, Nov 26 2021, 20:14:08) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import urllib >>> import urllib.request >>> type(urllib) <class 'module'> >>> type(urllib.request) <class 'module'> >>>
If you look closely to each of the below objects, then you will notice an important difference.
>>> urllib.__path__ ['/usr/lib/python3.8/urllib'] >>> urllib.request.__path__ Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: module 'urllib.request' has no attribute '__path__'
1. How Does Python locate modules
Generally speaking, when you ask Python to import a module, python looks to your filesystem for corresponding source files and loads that code. But here the important questions is how python knows where to look ? Python finds that out from sys.path
. It looks into first directory of sys.path
. If no matches found in the first directory then it checks the next and so forth until a match is found or python runs out of entries in sys.path
in which case a an import error is raised. Let's explore this further through Python Interpreter.
root@cyberithub:~# python3 Python 3.8.10 (default, Nov 26 2021, 20:14:08) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import sys >>> sys.path ['', '/usr/lib/python38.zip', '/usr/lib/python3.8', '/usr/lib/python3.8/lib-dynload', '/usr/local/lib/python3.8/dist-packages', '/usr/lib/python3/dist-packages'] >>>
Remember that sys.path is a general list so we can examine its contents by indexing and slicing. We can check the first entry of sys.path by using it like below. You can see that first entry is an empty string. This happens when you start the python interpreter with no arguments and it instructs python to search modules in current directory.
>>> sys.path[0] ''
To really get a feel for sys.path, let's create a directory called hello_world and a python source file called hello_test.py which will contain a function called hello(). This function will have the functionality to print a statement "Hello from CyberITHub !!"
on the output as you can see below.
root@cyberithub:~# mkdir hello_world root@cyberithub:~# cd hello_world/ root@cyberithub:~/hello_world# nano hello_test.py def hello(): print('Hello from CyberITHub !!') root@cyberithub:~/hello_world# python3 Python 3.8.10 (default, Nov 26 2021, 20:14:08) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import sys >>> sys.path.append('hello_test') >>> import hello_test >>> hello_test.hello() Hello from CyberITHub !!
2. Using PYTHONPATH
PYTHONPATH environment variable is a list of path that are added to sys.path
when Python starts. The format of PYTHONPATH
is same as your platform PATH variable. In Windows, it is a semi-colon separated list of directories while on Linux and MAC, it is colon separated list of directories. To see how PYTHONPATH works, let's add hello_world
to it before starts python again. In Windows, you can use set command and in Linux or MAC if you are using bash shell then use export command.
root@cyberithub:~# export PYTHONPATH=hello_world root@cyberithub:~# python3 Python 3.8.10 (default, Nov 26 2021, 20:14:08) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import sys >>> [p for p in sys.path if 'hello_world' in p] ['/root/hello_world'] >>> import hello_test >>> hello_test.hello() Hello from CyberITHub !! >>>
3. Basic Package Structure
To create a package directory, first you need to create a package root directory somewhere in sys.path
, then in that directory you create a file called __init__.py
. This file which is called a package init file will make the package a module.
path_entry/
|
|__my_package/
|
|__ __init__.py
To understand this further, let's create a directory called example. Then to convert this directory into a package, create __init__.py
file inside it. On Windows, you can use type command to create the file and on Linux or MAC Systems, you can use touch command as shown below.
root@cyberithub:~# mkdir example root@cyberithub:~# touch example/__init__.py
Now if you start the Interpreter and try to import the directory then you can see it as a module.
root@cyberithub:~# python3 Python 3.8.10 (default, Nov 26 2021, 20:14:08) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import example >>> type(example) <class 'module'> >>>
To see the role that __init__.py
plays in the functioning of a package, check the __file__
attributes of the example
package.
>>> example.__file__ '/root/example/__init__.py'
So we see that example is a module and the source file that is imported when example is imported is the package __init__.py
file in the example directory. In other words, a package is just a directory containing a file name __init__.py
.
To see that __init__.py is actually executed like any other module when you import example, let's add a small bit of code to it as shown below. Then start the interpreter again using python3
command and try to import example to see if the print statement shows on the output.
root@cyberithub:~# cd example/ root@cyberithub:~/example# nano __init__.py print("Hi, This is from CyberITHub !!") root@cyberithub:~/example# cd .. root@cyberithub:~# python3 Python 3.8.10 (default, Nov 26 2021, 20:14:08) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import example Hi, This is from CyberITHub !! >>>
4. Sub-packages
To really see how packages provides high level structure to Python code, let's see how we can add more layers of packages to the example hierarchy. We are going to add a sub-package called example_app
which is going to contain code to display a print statement. So first let's create a new directory and package __init__.py
file.
root@cyberithub:~# mkdir example/app root@cyberithub:~# touch example/app/__init__.py root@cyberithub:~# python3 Python 3.8.10 (default, Nov 26 2021, 20:14:08) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import example.app >>>
Now, let's create another Python source file called testapp.py
under example/app
directory. Then start the Python Interpreter again and try to import example
, example.app
and example.app.testapp
. You will see that all of them will be imported just fine.
root@cyberithub:~# touch example/app/testapp.py root@cyberithub:~# python3 Python 3.8.10 (default, Nov 26 2021, 20:14:08) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import example >>> import example.app >>> import example.app.testapp >>>