Most medium to large programs are organized into modules. This way, it becomes possible to logically separate various parts of a program based on their functionality.

Literally speaking ,a module is just a regular Python file that is created with an intention of being imported by scripts, other modules or even directly from the shell. A module must have a .py extension for it to be importable.

Consider the following example.

Example of a module 

#spam.py

def add(a, b):
     return f"{a} + {b} = { a + b}"

def sub(a, b):
     return f"{a} - {b} = { a - b}"

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

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

In the above example, we have a module called "spam.py" where we have defined functions for performing simple arithmetic calculations. We just defined the functions without using them, we can then import the module from elsewhere where the functions are needed.

Importing modules

To import a module we use the import statement which is basically comprised of the import keyword followed by the name of the module(excluding the .py part) to be imported. 

import module

For example to import the spam module from another module called foo.py,  we can do it as shown below.

#foo.py

#import the spam module
import spam

#Use the functions defined in spam
spam.add(10, 20)
spam.prod(3, 4)
spam.div(20, 5)
spam.sub(30, 10)

10 + 20 = 30
3 x 4 = 12
20 / 5 = 4.0
30 - 10 = 20

As shown above, the import operation compiles the code from the imported module and creates a module object with the same name. We then use the module object to access the attributes and objects such as functions and classes that are defined in the module.

Renaming the imported module

Sometimes we may want an imported module to appear under a different name where it is imported, this can be useful for two main reasons.

  1. To avoid conflicts if there are other objects that have the same name.
  2. To use a more convenient and easier to use name. We can for example use a shortened form if the actual name is too long or hard to spell. 

We can achieve this by using the import statement with the as clause.

Consider the following example.

#foo.bar

# import the spam module with a different name
import spam as sp

print(sp.add(10, 20))
print(sp.prod(3, 4))
print(sp.div(20, 5))
print(sp.sub(30, 10))

10 + 20 = 30
3 x 4 = 12
20 / 5 = 4.0
30 - 10 = 20

In the above example, we have imported the spam module with the name sp.

Import multiple modules

To import multiple modules at the same time, we can use multiple import statements,  for example:

import module1
import module2
import module3

But if convenience is something to factor in, we can use just a single import statement and supply the module names in a comma-separated manner.

import module1, module2, module3

Import individual objects from a module.

In some cases, we just need to use a small part of a module, for example in our spam module, we may just be in need of just one or two function. In such a case, it may be needless to load the entire module and doing so can actually lead to unnecessary complexity in our code as we will end up loading all the objects in the module but actually using just a few of them.

To achieve this, we use the import statement with the from clause. This way, we  import only those objects(functions, classes, etc) that we actually need. The syntax is as shown below:

from module import object1, object2, object3
#foo.py

#import only the functions that we need from spam
from spam import add, prod

print(add(5, 7))
print(prod(8, 9))

5 + 7 = 12
8 x 9 = 72

In the above example we imported, only two function, add() and prod() from the spam module. This helps avoid loading the rest of objects from the module that we would not have used.

We can also use the from clause together with as in order to import the objects under a different name.

#foo.py

#import only the functions that we need from spam
from spam import add as addition, prod as product

print(addition(5, 7))
print(product(8, 9))

5 + 7 = 12
8 x 9 = 72

Python offers a convenient syntax for importing all objects from a module, this relieves us from typing all the names one by one. The syntax is as shown below.

from module import *

The above syntax tells Python to import everything from the module. For example if we use it with our spam module, all the four functions will be loaded automatically.

#foo.py

from spam import *

#all the functions from spam are now imported
print(prod(10, 2))
print(sub(8, 4))
print(div(4, 2))
print(add(5, 5))
10 x 2 = 20
8 - 4 = 4
4 / 2 = 2.0
5 + 5 = 10

Modules from the standard Library

Python have a huge number of modules available in its standard library. This are modules that already exists  and we, therefore,  just need to import them before use. Some of the modules you may already be familiar with, such as math, random, time, etc. 

Use a module from the standard library

#import the time module from the standard library
import time

#get the current time
now = time.time()

#print a humen friendly date
print(time.ctime(now))

In the above example, we imported the time module from the standard library. We then used the time() function together with the ctime() functions from the module to get the current date and time.

In the following example, we use some objects from the math module.

#import some objects from the math module
from math import pi, sqrt, lcm

#the value of pi
print(pi)

#the square root of 5
print(sqrt(25))

# get lcm of 3, 4, and 5
print(lcm(3, 4, 5))