VMware ESXi and vSphere Cluster Management
What Are Python Modules?
Learn what Python modules are, why they are useful, and how to import standard-library and custom modules safely.
A module is an importable unit of Python code, commonly represented by a source file with the .py extension. A module groups related executable code and data so another Python file can reuse it.
A module can define functions, classes, constants, variables, and top-level statements that execute when the module is imported. The same file can be imported by another program or executed directly as a script.
Why Use Modules?
- Organization: Larger programs can be divided into focused, manageable files.
- Reuse: Functions, classes, constants, and other values can be used by multiple programs.
- Separation of responsibilities: One module might handle text processing while another handles user interaction or database access.
- Fewer name conflicts: Names remain inside a module's namespace unless you explicitly import or reference them.
- Access to existing code: Python includes a standard library, and third-party libraries provide additional reusable code.
The standard library is the collection of modules and packages distributed with Python for common tasks. A third-party library is installed separately, usually with a package manager such as pip.
What Is Inside a Module?
A module's attributes are the named objects associated with it. These can include functions, classes, constants, variables, and names imported from other modules.
A module also provides a namespace: a mapping between names and objects in that module. With a whole-module import, access an attribute using qualified access:
module_name.attribute_name
For example, math.pi refers to the pi attribute in the math module.
The built-in dir() function lists names available on an object, including a module:
import math
print(math.sqrt(25))
print("pi" in dir(math))
dir(math) also includes implementation-related names, so it is useful for exploration but is not always a complete description of the public API.
Importing an Entire Module
Importing is the mechanism Python uses to locate a module, load it, execute its top-level code when needed, and bind it in the importing file. The basic syntax is import module_name:
import math
radius = 3
area = math.pi * radius ** 2
print(area)
After import math, the name math is bound in the current file. Its members are accessed with dot notation, such as math.pi and math.sqrt(25).
Imports can use dotted module paths when a module belongs to a package:
import package.module
package.module.some_function()
Packages are introduced later in this lesson; the important point is that the dotted path identifies a module inside a package namespace.
Importing Standard-Library Modules
The standard library includes many modules. For example, math supplies mathematical constants and functions, while datetime supplies date and time types.
| Syntax | Name bound locally | How members are accessed | Typical use | Namespace consideration |
|---|---|---|---|---|
import math | math | math.sqrt(25) | Keep the module boundary visible | Only the module name is added locally |
import math as m | m | m.sqrt(25) | Use a shorter or conventional name | The alias must be clear to readers |
from math import sqrt | sqrt | sqrt(25) | Use one explicitly selected member | The name can collide with a local name |
from math import sqrt as square_root | square_root | square_root(25) | Use a descriptive local alias | The alias changes only the local binding |
from math import * | Many names | sqrt(25) | Rarely appropriate in application code | Names can overwrite or obscure existing names |
Importing Selected Names
The from ... import ... form binds selected names directly into the current namespace:
from math import sqrt, pi
radius = 3
area = pi * radius ** 2
print(sqrt(area))
Because sqrt and pi are bound locally, you do not write math.sqrt or math.pi in this example. You can also rename a selected member with as:
from datetime import date as Date
print(Date.today())
An alias is an alternate local name introduced with the as keyword. Aliases can improve readability, follow a widely used convention, or prevent a conflict with a local name.
Explicit imports are generally preferable to wildcard imports such as from math import *. Wildcard imports make it difficult to tell where a name came from and increase the chance of collisions or accidental shadowing.
Writing a Custom Module
Suppose a project contains these two files in the same directory:
project/
app.py
text_tools.py
The text_tools.py file is a module:
DEFAULT_SEPARATOR = "-"
def make_slug(text):
return DEFAULT_SEPARATOR.join(text.lower().split())
The separate app.py script imports and uses it:
import text_tools
print(text_tools.make_slug("Python Modules Explained"))
The output is:
python-modules-explained
DEFAULT_SEPARATOR and make_slug are attributes of text_tools. The qualified call text_tools.make_slug(...) makes the source of the function clear.
Choose descriptive module filenames that are valid Python identifiers. Prefer names such as text_tools.py over vague names such as stuff.py, and avoid names that conflict with common libraries or standard-library modules.
python app.py
Run this command from the directory containing both files, or from the intended project layout where the local module is importable.
Direct Execution Versus Importing
A module can contain reusable definitions and also contain a small demonstration or command-line entry point. Python gives every module a special __name__ attribute.
When a file is run as the main program, its __name__ is "__main__". When the file is imported, __name__ usually contains the module's import name. This makes the following guard useful:
def greet(name):
return f"Hello, {name}!"
if __name__ == "__main__":
print(greet("reader"))
The greeting prints when the file is run directly, but not merely because another file imports it. A second file can use the definition without triggering the demonstration:
import greetings
print(greetings.greet("Ada"))
Not every small module needs a main guard. Use it when a module has behavior intended for direct execution, such as a demonstration, a quick test, or a command-line entry point.
What Happens During an Import?
On the first import of a module during a Python process, Python locates the module and executes its top-level statements. Definitions become available as module attributes, and top-level actions such as printing, reading input, or opening a file also happen at that time.
Python keeps loaded modules in sys.modules, its module cache. If another part of the same process imports the module again, Python normally reuses the cached module instead of executing its top-level code again.
import sys
print("math" in sys.modules)
This is why reusable modules should usually define functions and classes rather than performing repeatable work immediately at the top level. Call a function explicitly when the work should happen.
importlib.reload() can reload a module during interactive development, but it is not a general replacement for clean initialization. Reloading can leave existing references and objects in surprising states, so production designs should not depend on it.
How Python Finds Modules
Python must locate a module before it can import it. At a beginner level, think of the import search path as an ordered collection of locations. It commonly includes:
- The script location or current project location, depending on how the program is launched.
- Locations containing Python's standard library.
- Locations containing installed third-party packages.
- Additional entries recorded in
sys.path.
You can inspect the search path with:
python -c "import sys; print('\\n'.join(sys.path))"
This command helps diagnose an import problem. It is not normally necessary to edit sys.path manually as a project setup solution. A clear project layout and the intended environment are usually better fixes.
A local file can accidentally hide another module with the same name. For example, naming your own file math.py, random.py, json.py, or typing.py can cause Python to import that file instead of the expected standard-library or installed module.
When applicable, inspect the resolved source location:
python -c "import math; print(math.__file__ if hasattr(math, '__file__') else 'built-in module')"
Some modules are built into the Python interpreter and do not have a normal __file__ path. For an external dependency that is genuinely missing, installation may be appropriate:
python -m pip install package_name
Use pip for intended third-party dependencies. It is not needed to import an ordinary local file such as text_tools.py.
Modules, Packages, Libraries, and Scripts
| Term | What it represents | Typical contents | Example |
|---|---|---|---|
| Module | One importable unit, typically one source file | Functions, classes, constants, variables, and statements | text_tools.py |
| Package | A namespace that groups related importable modules | Several modules and possibly subpackages | project_tools.text |
| Library | A broad term for reusable code intended for multiple programs | One module, many modules, or one or more packages | The Python standard library |
| Application script | A file intended to perform a program's task when run | Program flow, input handling, and calls to reusable modules | app.py |
A package is an organizational layer above individual modules. Package structure, package initialization, and distribution are separate topics; for now, remember that a package provides a shared namespace for related modules.
Troubleshooting Import Problems
ModuleNotFoundError for a Local Module
Common causes include:
- The module file is not in an importable project location.
- The program was launched from an unexpected working or project context.
- The filename does not match the import name.
- The module belongs to a package but is being imported without the correct package path.
Check directory and file names, run the program using the intended project layout, and use the correct import path. Inspect sys.path to understand where Python is looking rather than routinely modifying it.
AttributeError After Importing
The requested name might not be defined, might be misspelled, or might belong to a different module with the same name. Check the available names:
import text_tools
print(dir(text_tools))
print(text_tools.__file__)
If the module is only partially initialized, a circular import may also be involved. Simplifying dependencies and moving shared definitions into a lower-level module can help.
A Local File Hides Another Module
Rename a local file that has a common dependency name, such as random.py or json.py. If stale bytecode appears to be involved, remove the relevant __pycache__ files and verify the loaded module's origin with module_name.__file__.
Top-Level Code Does Not Run a Second Time
This is normally expected: the module is already present in sys.modules. Put repeatable behavior in a function and call that function explicitly. Use importlib.reload() only deliberately in interactive or development situations.
Importing Produces Unexpected Output or Side Effects
Printing, requesting input, modifying files, or performing other work at module level runs during the first import. Keep reusable definitions at module level, but place demonstrations and command-line behavior behind if __name__ == "__main__":.
Key Points
- A module is commonly a
.pyfile containing related Python code and data. - Functions, classes, constants, variables, and imported names can become module attributes.
import modulekeeps access explicit throughmodule.attribute.from module import namebinds selected names locally, but can create collisions.- Use aliases with
aswhen they improve clarity or prevent conflicts. - Python searches locations in
sys.pathand caches loaded modules insys.modules. - Use descriptive filenames and avoid names that hide standard-library or installed modules.
- The
__name__ == "__main__"guard separates direct-run behavior from importable definitions. - A package groups modules, while a library is a broader term for reusable code.