Python Modules and Packages

Photo by CHUTTERSNAP on Unsplash

Python Modules and Packages

Essentially, every Python file is a module that can be imported into other files or modules. Modules can contain definitions, statements, functions or classes. Modules allow code to be reused.

In Python, Packages are a collection of modules and are used to structure modules. A package is typically implemented as a folder or directory containing an __init__.py file.

Modules and Packages help us in working on large projects by breaking the code into related functionality.

Built-in and External Modules

Built-in modules are installed with the standard Python installation by default. Python comes with a library of standard modules, these provide access to operations that are not part of the core of the language. We can start working with them right away after the Python installation. Refer to the link https://docs.python.org/3/py-modindex.html for the Python module index.

External modules have to be externally downloaded and installed to start working with them. The Python Package Index (PyPI) is a repository of software for the Python programming language (https://pypi.org/), which helps you find and install software developed and shared by the Python community.

pip is the package installer for Python. One can use pip to install packages from the Python Package Index and other indexes. Details of pip can be found at https://pip.pypa.io/en/stable/.

pip install package-name
or 
python -m pip install package-name

Working with Modules

Python code in one module gains access to the code in another module by the process of importing it. The import statement is the most common way of doing this. The import statement combines two operations; it searches for the named module, and then it binds the results of that search to a name in the local scope.

# Snippet for importing math module and calculating Square root of a number
import math

x = math.sqrt(4)
print(x)

# Output
2

There are various ways to import functions or modules.

# Importing a module. Need to use module name as prefix for using its functions
import math
x = math.sqrt(4)

# Importing a specific function from math module. Function can be used without any module prefix.
from math import sqrt
x = sqrt(4)

# Importing all functions from a module. No need to use module prefix but loads all the functions into the namespace.
from math import *
x = sqrt(4)

# Module aliasing. Alias name to be used as a prefix.
import math as mt
x = mt.sqrt(4)

In general, it is better to be explicit importing than implicit, to conflicts while using the same functions from different modules.

dir() built-in function returns a list of names in the current local scope. With an argument, it returns a list of valid attributes for that object.

>>> import math
>>> import os
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'math', 'os']
>>> dir(math)
['__doc__', '__file__', '__name__', '__package__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'hypot', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc']

if __name__ == '__main__'

In Python, the special name __main__ is used for two important constructs:

  1. the name of the top-level environment of the program, which can be checked using the __name__ == '__main__' expression; and

  2. the __main__.py file in Python packages.

Both of these mechanisms are related to Python modules; how users interact with them and how they interact with each other.

__main__ is the name of the environment where top-level code is run. “Top-level code” is the first user-specified Python module that starts running. It’s “top-level” because it imports all other modules that the program needs. Sometimes “top-level code” is called an entry point to the application.

# The result of typing __name__ in Python REPL
>>>__name__
'__main__'

Some modules contain code that is intended for script use only, like parsing command-line arguments or fetching data from standard input. If a module like this was imported from a different module, for example to unit test it, the script code would unintentionally execute as well.

This is where using the if __name__ == '__main__' code block comes in handy. Code within this block won’t run unless the module is executed in the top-level environment. This is often used either to provide a convenient user interface to a module, or for testing purposes.

# hello.py
# Without if __name__ == '__main__'
$ vim hello.py
def main():
    print("Hello")

$ python hello.py # Returns none

# With if __name__ == '__main__'
$ vim hello.py
def main():
    print("Hello")

if __name__ == '__main__':
    main()
$ python hello.py
$ Hello

Package Structure

The basic Structure of a Python package or application taken from https://packaging.python.org/en/latest/tutorials/packaging-projects/#

package/
├── LICENSE
├── pyproject.toml
├── README.md
├── src/
│   └── example_package/
│       ├── __init__.py
|       ├── example1.py
│       └── example2.py
└── tests/

Some may use setup.py or setup.cfg files are also in their structure, using toml file for configurations is evolving.

In general __init__.py can be empty, but if a package’s __init__.py code defines a list named __all__, it is taken to be the list of module names that should be imported when from package import * is encountered.

Thank you for reading, if you like this article, please like and share.