What are Python modules and how to create your own custom module?



What are modules in Python?

A module is a file containing Python definitions and statements such as variables, functions, classes, etc. It makes coding much more easy, fast and simple. The advantage of coding in python is it supports modules and there are already a huge number of built-in modules or we also call libraries. In addition, we can also create our own custom module and use it whenever required.

When our program becomes longer, it becomes hard to maintain. Therefore, splitting it into several files makes code maintenance easier. Moreover, the built-in module helps in executing programs more intelligently and effectively with the lesser block of code.

To support a module, Python has a way to put definitions in a file and use them in a script or in an interactive instance of the interpreter. Such a file is called a module. And the definitions from a module can be imported into other modules or into the main program.

How to create a custom module?

There is no special way to create a module in python. A module is just a file containing Python definitions and statements. The file name is the module name with the suffix .py appended and saved in the current directory (folder) so that we can import it into our main program. For example, calculation.py is a python file or script and calculation is a module name.

Example:

# calculation.py

def sum(a,b):
    return a + b
def mul(a,b):
    return a * b
def sub(a,b):
    return a - b
def div(a, b):
    return a / b

In the above example, we just created a calculation module that does simple mathematical operations such as addition, multiplication, subtraction, and division. Now we will see how to import the calculation module in our main program and use its definitions.



Importing module

There are two ways where we can import the module: directly using the import statement at the beginning of the module or by using a from clause at the beginning of the statement.

To make the module accessible, make sure that all your modules and scripts are saved in the current directory or in the same folder. Otherwise, your module won’t be accessible.

I will be explaining based on the module created in the above example i.e. module calculation that does a simple mathematical operation.

1. Using import statement at the beginning of the module.

Two ways to import a module using import statement:

  1. import module
  2. import module as alias  (alias can be any string name)

1.1 Import module

Syntax:

import calculation

Each module has its own private symbol table, which is used as the global symbol table by all functions defined in the module. Thus, a module can use global variables in the module without worrying about accidental clashes with a user’s global variables. For that, we have to use the module name to access its functions: module.Itemname.

Example: calculation.sum to access sum operation from a calculation.py

For example, we will now use our calculation module in our main program named main.py using the import module method.

# main.py

import calculation # Importing calculation module
a = calculation.sum(10, 5)
print(f"sum:{a}")

m = calculation.mul(10, 5)
print(f"mul:{m}")

s = calculation.sub(10, 5)
print(f"sub:{s}")

d = calculation.div(10, 5)
print(f"div:{d}")

Output:

sum:15
mul:50
sub:5
div:2.0

1.2 Import module as an alias

Syntax:

import calculation as calc 

If the module name is followed by “as”, then the name following “as” is bound directly to the imported module. Using alias helps to avoid name collision.

Example:

# main.py

import calculation as calc # Importing module as an alias
a = calc.sum(10, 5)
print(f"sum:{a}")

m = calc.mul(10, 5)
print(f"mul:{m}")

s = calc.sub(10, 5)
print(f"sub:{s}")

d = calc.div(10, 5)
print(f"div:{d}")

Output:

sum:15
mul:50
sub:5
div:2.0


2. Using from clause to import module

Two ways to import a module using from clause:

  1. from module import *
  2. from module import itemname

It is not mandatory to place an import statement at the beginning of the module. We can use from clause to import names of a module directly into importing module’s symbol table.

2.1 from module import *

Syntax:

from calculation import *

If the list of identifiers is replaced by a star (‘*’), all public names defined in the module are bound in the local namespace for the scope where the “import” statement occurs. However, in general, the practice of importing * from a module is not recommended, since it often causes poorly readable code. However, it is okay to use it to save typing in interactive sessions.

Example:

# main.py

from calculation import *
a = sum(10, 5)
print(f"sum:{a}")

m = mul(10, 5)
print(f"mul:{m}")

Output:

sum:15
mul:50

2.2 from module import item name

Syntax:

from calculation import sum

This is used when we want to import a particular definition from the module. For example, if we want to import the only sum from a module calculation, we have to use from clause. It will check if the imported module has an attribute by that name and if the attribute is not found, “ImportError” is raised.

Note: we can import more than one definition separated by a comma. For example >>>from calculation import sum, mul, div

Example:

# main.py

from calculation import sum
a = sum(10, 5)
print(f"sum:{a}")
m = mul(10, 5)    # mul definition is not imported so it raises an error
print(f"mul:{m}")

Output:

sum:15        
Traceback (most recent call last):
  File "c:/Users/Dawa Penjor/Desktop/main.py", line 5, in <module>
    m = mul(10, 5)
NameError: name 'mul' is not defined


Executing modules as scripts

When you run a module as a script, the code in the module will be executed just as you imported.

New module: (New file addition.py is created and I am using addition module to explain the concept of executing modules as scripts)

# addition.py

def sum(a,b):
    return a + b
print("I am executed from addition module.")

Example:

# main.py

import addition
s = addition.sum(10,5)
print(s)

Output:

I am executed from addition module.
15

So, if you want to make the file usable as well as an importable module, you should set __name__ to __main__.  In this case, the code that parses the command line only runs if the module is executed as the “main” file.

Modifying the above module addition:

# addition.py

def sum(a,b):
    return a + b
if __name__ == '__main__':
    print("Executes only if you run as a script, not as a module")

Output:

Executes only if you run as a script, not as a module

Now, importing addition.py as a module in main.py

# main.py

import addition
s = addition.sum(10,5)
print(s)

Output:

15 # only sum function executed

Note: Now we could see that statement inside the __name == ‘__main__’ in an addition.py is not executed.



What is __main__ and __name__?

‘__main__’ is the name of the scope in which top-level code executes.

‘__name__’ returns the name of the file. A module’s __name__ is set equal to ‘__main__’ when read from standard input, a script, or from an interactive prompt. In case, if the file is imported as a module, the module’s __name__ is set to its actual file name.

The module search path

When the module is imported, the interpreter first searches for a built-in module with that name. If not found, it then searches for the file name appended by .py in a list of directories given by the variable sys.path, which is obtained from a module named sys. The variable sys.path is a list of strings that determines the interpreter’s search path for modules. It is initialized to a default path taken from the environment variable PYTHONPATH, or from a built-in default if PYTHONPATH is not set.

sys.path is initialized from these locations:

  • The directory containing the input script (or the current directory when no file is specified).
  • PYTHONPATH environment variables which contains a list of directory names.
  • The installation-dependent default. (when python was first installed in the device)

Syntax:

import sys  # Importing built-in sys module
print(sys.path)

Output:

['c:\\Users\\Dawa Penjor\\Desktop', 
'C:\\Users\\Dawa Penjor\\AppData\\Local\\Programs\\Python\\Python38\\python38.zip', 'C:\\Users\\Dawa Penjor\\AppData\\Local\\Programs\\Python\\Python38\\DLLs', 'C:\\Users\\Dawa Penjor\\AppData\\Local\\Programs\\Python\\Python38\\lib', 
'C:\\Users\\Dawa Penjor\\AppData\\Local\\Programs\\Python\\Python38', 
'C:\\Users\\Dawa Penjor\\AppData\\Roaming\\Python\\Python38\\site-packages', 'C:\\Users\\Dawa Penjor\\AppData\\Local\\Programs\\Python\\Python38\\lib\\site-packages']

We can also modify the PYTHONPATH using standard list operations:

import sys
sys.path.append('/ufs/guido/lib/python')

Standard module in python

Python comes with a library of standard modules which we called as built-in modules. These modules are already built into the interpreter to provide access to operations that are not part of the core of the language but are nevertheless imported either for efficiency or to provide access to some other built-in functionality. For example such as math module, random module, DateTime module, sys module, and many more modules are already built into every Python interpreter. Modules have been written either in Python itself or in C.

To display the available modules in Python, use the statement:

help('modules')

You will see all the built-in modules displayed as per your python version.



The dir() function

The built-in function dir() is used to find out which names such as variables, modules, functions, etc. are defined in a module. It returns in a sorted list of strings. However, it does not list the names of built-in functions and variables.

For example, to check the list of functions in the built-in math module:

import math # Importing math module
dir(math)

Output: (All the available math module functions are displayed)

['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 
'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees',
'dist', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 
'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 
'lcm', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'nextafter', 
'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh',
 'tau', 'trunc', 'ulp']

If no arguments are passed inside the dir() function, it will list the names we have defined at present.

Example:

dir()

Output:

['__annotations__', '__builtins__', '__doc__', '__loader__', 
'__name__', '__package__', '__spec__', 'builtins', 'math']

If you want to check the list of all the built-in functions and variables, it is defined in the standard module called builtins.

Syntax:

import builtins
dir(builtins)