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.

SyntaxName bound locallyHow members are accessedTypical useNamespace consideration
import mathmathmath.sqrt(25)Keep the module boundary visibleOnly the module name is added locally
import math as mmm.sqrt(25)Use a shorter or conventional nameThe alias must be clear to readers
from math import sqrtsqrtsqrt(25)Use one explicitly selected memberThe name can collide with a local name
from math import sqrt as square_rootsquare_rootsquare_root(25)Use a descriptive local aliasThe alias changes only the local binding
from math import *Many namessqrt(25)Rarely appropriate in application codeNames 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

TermWhat it representsTypical contentsExample
ModuleOne importable unit, typically one source fileFunctions, classes, constants, variables, and statementstext_tools.py
PackageA namespace that groups related importable modulesSeveral modules and possibly subpackagesproject_tools.text
LibraryA broad term for reusable code intended for multiple programsOne module, many modules, or one or more packagesThe Python standard library
Application scriptA file intended to perform a program's task when runProgram flow, input handling, and calls to reusable modulesapp.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 .py file containing related Python code and data.
  • Functions, classes, constants, variables, and imported names can become module attributes.
  • import module keeps access explicit through module.attribute.
  • from module import name binds selected names locally, but can create collisions.
  • Use aliases with as when they improve clarity or prevent conflicts.
  • Python searches locations in sys.path and caches loaded modules in sys.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.