We use the import
statement when we want to use code from another python file(module) or library.
The import
keyword is the primary tool used to create import statements.
Basically, an import
statement has the following syntax:
import <module>
We simply use the import
keyword followed by the name of the module we want to import.
In the above example, we imported a module called 'time'. This module already exists ready for use in Python's standard library. We then used a function called ctime()
from the time
module.
The import process
Several things happens when we use an import
statement, they are as outlined below:
- The
import
statement searches for the module specified in the statement. - If the module is found.
- its code is executed.
- The imported module is added to the current namespace, allowing its contents to be accessed using the dot notation (e.g.
module.function()
to access a function defined in the module)
- If the module is not found, a
ModuleNotFoundError
exception is raised.
Note that when the module is imported, its code is actually executed, this means that if there are any statements, variable declarations or function calls at the top level of the module, they will be executed once the module is imported, and any resulting changes or actions will take place immediately. Consider the following example:
foo.py
#foo.py
#this module will be imported
def add(a, b):
print(f'{a} + {b} = {a + b}')
a = 10
b = 20
add(a, b)
10 + 20 = 30
In the above example, we defined a module called foo.py
which is imported by main.py
.
Note that the output from the function call in foo.py
is automatically seen when the module is imported in main.py
. This should make you define and use modules with caution, for example, having unnecessary statements and function calls at the top-level of a module means that they will be propagated where the module is imported.
Advanced Import statements
The import
statement is is more flexible than for simply importing a single module by its name. In this section we will see how we can use the import
statement more flexibly to control how imports works.
Import multiple modules at once
We can import multiple module in the same import
statement by separating their names with comas. The syntax is as shown below:
import <module1>, <module2>, <module3>, ...
In the above example, we imported three built-in modules in the same import statement, time
, random
and math
. You can import as many modules as necessary by separating their names with commas.
Importing a module under a different names
Sometimes we may want to import a module such that we can access it with an alias name instead of its actual name. This may be the case for example if :
- There are multiple modules with similar names which can lead to conflicts.
- We want to use a more convenient name, for example if the name is too long, we may want to use a shorter more convenient name..
- We want to use a more intuitive or descriptive name for the module.
- We want to rename the module for organizational or stylistic reasons
To import a module under a different name, we use the import
statement with an as
clause. The basic syntax is as shown below:
import <module> as <new_name>
In the above example, we imported the built-in datetime
module with an alias name, ''dt
". This way, the module becomes accessible under the alias name.
Importing specific objects from a module
Note that in all the previous examples, we imported an entire module but ended up using just one or two functions from the module.
In case when we know that we are simply going to use only specific objects(functions, classes, etc ) from a module, we can use the import
statement with a from
clause to specify only those objects that we want to import. The syntax is as shown below:
from <module> import <object1>, <object2>, <object3>....
Only the specified objects will be imported. An object refers to a function, a class, a variable, e.t.c
In the above example, only sqrt
, sin
and log
functions are imported from the builtin math
module.
If necessary, you can alias the imported object using the as
clause so that it will be available with the alias name instead of its actual name.
Import Everything
In case where you want to import all objects from a module, you can use the import
statement with an asterisk(*
), the syntax is as shown below:
from <module> import *
Note that this will make any object in the specified <module>
get imported and be available in the program's namespace.
While this syntax may seem convenient, it should be used with caution and only when necessary or you know exactly what you are doing. This is because it may lead to unnecessary complexity as you may not end up using all the imported objects, as well as potential name conflicts.
As you can see, in the above example, after using the from math import *
, all functions defined in the math
module gets imported and added to the program's namespace.
The ModuleNotFoundError
Exception
As earlier mentioned, whenever import statement fails to locate the module with the specified name, a ModuleNotrFoundError
exception is raised.
This exception is especially common when we misspell the name of the module we want to import
In the above example, we were intending to import the builtin module called datetime
but we deliberately misspelled its name leading to the ModuleNotFoundError
exception being raised. In practical scenarios, you will not misspell the names intentionally.
In cases where we anticipate that the ModuleNotFoundError
may be raised, we can wrap the import
statement in a try
block and place the corrective action in the except
block. For example, this may be the case when we are not sure whether a third-party module is currently installed in the system.
Circular Imports
One of the most dreaded exceptions is the one that occurs due to circular imports.
A circular import happens when two or more modules are trying to import each other, creating a never-ending import loop. This can happen when there is a dependency between the modules. For example consider the following two modules:
#foo.py
import spam
#spam.py
import foo
Trying to use an object from a module when there is circular import will lead to an ImportError
exception.
When code in foo.py
tries to access an object from spam.py
, Python will try to import spam.py
first. But since spam.py
also imports objects from foo.py
, it will again try to import foo.py
, causing a never-ending loop.
Good practices with imports
- Conventionally, all
import
statements should be placed at the top of the file before any other code. This allows for easier visibility and organization of imported modules. - Only import what you need, and generally avoid using imports with asterisk(
*
) syntax. This helps reduce memory usage and potential name conflicts. - When using aliasing with the
as
clause, ensure that the alias names are meaningful and do not conflict with those of existing objects. - Avoid circular imports.