In this article, we will be learning about modules in Python. Let us begin by defining the term module.
A module is a file that consists of constants, variables, functions, and classes. In python, modules have the extension .py
. It can be built-in or user-defined.
A module provides code reusability. We can import modules in a program (which we will be learning in the next section) and use its functions, classes, and variables so that we do not have to write them repeatedly hence reducing the length of the code.
For example, let’s start by creating a module, factorial.py
.
File: factorial.py
SPEED_1 = 5
SPEED_2 = 10
def fact(number):
if number in (0, 1):
return 1
else:
return number * fact(number - 1)
Here, we have defined constants SPEED_1
and SPEED_2
with the values 5
and 10
and defined a function fact()
that takes a number as an input and returns its factorial.
In the next section, we will learn how to import modules and use their variables and functions in our code.
To import a complete module, Python provides us with a keyword import
. In the following example, we will import the factorial.py
module to calculate the factorial of a number.
File: test_factorial.py
import factorial
num = 5
factorial_5 = factorial.fact(num)
print("Factorial of %d is %d" %(num, factorial_5))
Here, we have accessed fact()
method of the factorial
module using the dot (.
) operator.
Output:
Factorial of 5 is 120
Now let’s say we want to use the factorial
module multiple times. To make our code compact, we can give alias name to the imported module by writing,
import factorial as f
Now, we can use SPEED_1
and fact()
method as
print("Factorial of %d is %d" %(f.SPEED_1, f.fact(f.SPEED_1)))
print("Value of SPEED_2 = %d" %(f.SPEED_2))
Which also gives the same output
Output:
Factorial of 5 is 120
Value of SPEED_2 = 10
Note: If we give alias f
to the module, the module name factorial
will not be recognized anymore.
What if we only want to import the variable SPEED_1
and the fact()
method? For this, we will only import SPEED_1
and fact()
as done below.
from factorial import fact, SPEED_1
In this case, we can directly write variable and method names to use them.
print(fact(5))
print(SPEED_1)
And we get the following output
Output:
120
5
We can also import all the functions, variables, and classes defined in the module using an asterisk (*
).
from factorial import *
Note: Let’s say we create a variable, a function, or a class in our code with the same name as defined inside the module. It can lead to the definition duplicacy. Therefore, this method is not recommended.
There can be cases where we would like to import from subdirectories. To achieve that, we can use the absolute path of the module.
Consider the following folder structure
my_project # root folder(level 0)
|-- test.py
|-- util
|-- printer.py
|-- source # folder at level 1
|-- code # folder at level 2
|-- factorial.py
If we want to use the fact()
method of the factorial
module, we will have to go all the way up to folder level 2 and import fact()
as shown.
File: test.py
from source.code.factorial import fact
print(fact(5))
Output:
120
But what if we have a deep or complex folder structure? In that case, it will be impractical to use absolute paths.
Here, __init__.py
comes into the picture.
We create an __init__.py
file inside a directory to be considered as a module. Also, inside the __init__.py
file, we can write the following code to reduce the path complexity for the above folder structure.
New folder structure
my_project # root folder(level 0)
|-- test.py
|-- util
|-- printer.py
|-- source # folder at level 1
|-- __init__.py
|-- code # folder at level 2
|-- factorial.py
Add the following code inside the __init__.py
file.
File: __init__.py
from .code.factorial import fact
Now, in our test.py file, we only have to write
from source import fact
print(fact(5))
Output:
120
Until now, we have learned about modules and how to import them. But how does the python interpreter find the modules we import?
First, the python interpreter looks for a built-in module. If the required module is not found, it looks into the directories mentioned in sys.path
.
The following code will print a list of values inside sys.path
.
from sys import path
print(path)
Output
[
'C:\\Users\\user\\PycharmProjects\\my_project',
'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python37-32\\python37.zip', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python37-32\\DLLs', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python37-32\\lib', 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python37-32','C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python37-32\\lib\\site-packages'
]
Process finished with exit code 0
The search order is,
PYTHONPATH
, which is an environment variable that contains a list of directoriesA module in a python script is imported only once by the interpreter for efficiency.
Consider the following module, printer.py
number = 5
print(number)
Now if we import this module in our script file as
>>> import printer
5
The value of number
is printed.
Now let’s modify the printer.py
module by changing the value of number
to 6
. But if we import the module again, we don’t see any output.
>>> import printer
5
>>> import printer
Why is it so?
If we import a module and make changes to it, those changes will not be reflected in the current script. For this, we need to either restart the interpreter or reload the module by using the reload()
function.
The reload()
function is defined inside the importlib
module which we need to import.
>>> import printer
5
>>> import printer
>>> from importlib import reload
>>> reload(printer)
6
Python provides us with a function dir()
which can be used to find the names that are defined in a module. It returns a sorted list with the names of the functions, variables, and classes of the module. For example
import factorial
print(dir(factorial))
We get,
Output:
[
'__builtins__',
'__cached__',
'__doc__',
'__file__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'fact',
'SPEED_1',
'SPEED_2'
]
Here, apart from the names defined inside the module factorial
, we get names with underscores. These are the default built-in python attributes provided to the module.
We already know that a module in Python is simply a Python script file with extension .py
. So, like any script file, the module can also be executed.
We can execute a module (printer.py
in our case) using cmd
on Windows or terminal
on Linux/Mac and run the following command.
python printer.py
And we get the output,
6
You may have noticed that we got the same output when we imported the printer.py
module in the Reloading a module
section. So, how do we differentiate between when we run the module as a script and when the file is imported as a module?
If the module is run as a script file, the python interpreter sets the special variable
__name__
to the value__main__
. If this file is imported as a module,__name__
will be set to the name of the module.
So, we add the following code where we check if the value of __name__
is equal to __main__
. If true, it will mean that the module is run as a script. Otherwise, it is imported as a module.
File: printer.py
SPEED_1 = 5
SPEED_2 = 10
def fact(number):
if number in (0,1):
return 1
else:
return number * fact(number - 1)
if __name__ == '__main__':
print(fact(5))
As imported
>> import printer
>> printer.fact(5)
120
As a script file
C:\Users\user\PycharmProjects\my_project> printer.py 5
120
In this section, we learned
Help us improve this content by editing this page on GitHub