# mymodule.py is a module
import mymodule
# mypackage/ with __init__.py is a package
import mypackage.submodule
Topics
20
Async Generators & Async Context Managers
Command-Line Interfaces (argparse)
Comprehensions & Generators
Concurrency (asyncio/threading/multiprocessing)
Data Types & Structures
Dataclasses & NamedTuples
Debugging & Profiling
Decorators
Descriptors & Properties
Exception Handling
File I/O & Context Managers
Functions & Scope
functools & Functional Programming Tools
Iterators & the Iterator Protocol
Logging
Magic Methods & Operator Overloading
Memory Management & Garbage Collection
Metaclasses & Class Customization
Modules & Packaging
Multiple Inheritance & MRO
Modules & Packaging
15 questions found
A module is a single .py file containing Python definitions and statements that can be imported. A package is a directory containing multiple modules plus an __init__.py file (making it importable as a namespace), allowing related modules to be organized hierarchically, e.g., `import package.module`.
Real-world example
A web application's codebase organizes routes.py, models.py, and utils.py as modules inside an `app` package, giving a clean `from app.models import User` import path.
Modules & Packaging;Virtual Environments & Dependency Management
__init__.py marks a directory as a regular Python package and runs when the package is first imported, letting you control what's exposed at the package level (e.g., re-exporting submodule contents), set up package-wide state, or simply exist as an empty file to establish the package structure. Since Python 3.3, packages can technically work without it (namespace packages), but explicit __init__.py remains the common convention.
# mypackage/__init__.py
from .models import User
from .utils import helper
__all__ = ['User', 'helper']
# now: from mypackage import User
Real-world example
A library's __init__.py re-exports key classes from internal submodules so users write `from mylib import Client` instead of the longer `from mylib.core.client import Client`.
Modules & Packaging;Multiple Inheritance & MRO
How does Python's module import system avoid re-executing a module multiple times when imported from different places?
IntermediatePython caches every imported module in sys.modules keyed by its fully qualified name. When any code does `import foo`, Python checks sys.modules first; if already present, it reuses the cached module object instead of re-running foo.py, ensuring module-level code executes exactly once per process and all importers share the same module object (and its state).
import sys
import json
print('json' in sys.modules) # True after first import
# Subsequent imports reuse the cached module -- no re-execution
import json as json2
print(json is json2) # True, same object
Real-world example
A configuration module that loads settings once at import time relies on this caching -- every part of the application importing `config` gets the same already-initialized settings object, not a fresh reload.
Modules & Packaging;Memory Management & Garbage Collection
What is the difference between an absolute import and a relative import within a package?
IntermediateAn absolute import specifies the full path from the top-level package (`from mypackage.utils import helper`), while a relative import uses leading dots to reference modules relative to the current module's position in the package (`from .utils import helper` for a sibling, `from ..core import Base` for a parent package). Relative imports only work within a package context (not in standalone scripts) and make internal restructuring easier since you don't hardcode the package's top-level name.
# Inside mypackage/subpkg/module.py
from . import sibling_module # relative: same package
from .. import top_level_module # relative: parent package
from mypackage.subpkg import sibling_module # absolute equivalent
Real-world example
A large internal package uses relative imports throughout its submodules so the entire package can be renamed or vendored into another project without rewriting every absolute import path.
Modules & Packaging;Functions & Scope
When you import a module, Python searches directories listed in sys.path in order: the directory of the script being run (or '' for interactive/current directory), directories from the PYTHONPATH environment variable, and standard installation-dependent paths (including site-packages). The first matching module found wins, which is why sys.path order and accidental name shadowing (e.g., a local file named `json.py`) can cause confusing import bugs.
import sys
print(sys.path) # list of directories searched, in order
sys.path.insert(0, '/custom/module/location') # prioritize a custom path
import my_custom_module
Real-world example
A developer's script mysteriously imports the wrong `requests` module because a local file named requests.py in the working directory shadows the installed package earlier in sys.path.
Virtual Environments & Dependency Management;Debugging & Profiling
What does the `if __name__ == '__main__':` idiom accomplish, and why is it important for modules?
IntermediateEvery module has a __name__ attribute set to '__main__' if run directly as a script, or to the module's actual name if imported elsewhere. Guarding script-execution code with `if __name__ == '__main__':` lets a file work both as a reusable importable module and as a standalone script, without running its script-only logic (like CLI parsing or test code) when imported by other code.
# mymodule.py
def main():
print('Running as a script')
if __name__ == '__main__':
main() # only runs when executed directly, not when imported
Real-world example
A data-processing module exposes reusable functions for import elsewhere, but also includes a `__main__` block so it can be run directly from the command line for quick manual testing.
Command-Line Interfaces (argparse);Modules & Packaging
A namespace package (PEP 420) is a package without an __init__.py that can span multiple directories or distributions -- Python implicitly recognizes any directory containing Python files as a namespace package portion, letting a single logical package (like `myorg.tools`) be split across separately installed distributions that merge into one importable namespace at runtime.
# No __init__.py needed:
# dist1/myorg/tools/a.py
# dist2/myorg/tools/b.py
# Both contribute to the same 'myorg.tools' namespace package
import myorg.tools.a
import myorg.tools.b
Real-world example
A large organization splits a monorepo's internal tooling into separately versioned pip packages (myorg-tools-network, myorg-tools-storage) that all contribute submodules to the same `myorg.tools` namespace.
Virtual Environments & Dependency Management;Modules & Packaging
How does pyproject.toml serve as the modern standard for defining a Python package's build configuration and dependencies?
Intermediatepyproject.toml (PEP 518/621) is the standardized configuration file that specifies build-system requirements (like setuptools or poetry), project metadata (name, version, dependencies), and tool-specific configuration (black, pytest, mypy) in one place, replacing the older, less standardized combination of setup.py, setup.cfg, and various tool config files.
# pyproject.toml
[project]
name = "mypackage"
version = "1.0.0"
dependencies = ["requests>=2.28", "click>=8.0"]
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
Real-world example
A new open-source project adopts pyproject.toml exclusively, avoiding a legacy setup.py entirely, and configures both its build system and its black/pytest settings in the same file.
Virtual Environments & Dependency Management;Modules & Packaging
How does Python resolve circular imports, and what strategies avoid the resulting ImportError?
AdvancedA circular import occurs when module A imports module B, and B (directly or indirectly) imports A, potentially trying to access a name in A before A has finished executing (since A is partially initialized in sys.modules during the circular import). Common fixes include: restructuring code to remove the cycle, moving the import inside a function (deferred/local import) so it happens after both modules are fully loaded, or importing the module itself rather than specific names from it (`import a` then `a.something` instead of `from a import something`).
# a.py
import b
def func_a():
return b.func_b()
# b.py
def func_b():
import a # deferred import avoids circular ImportError at module load time
return 'from b'
Real-world example
Two tightly-coupled modules in a Django app (models.py and signals.py) resolve a circular import by moving one import inside a function body, deferring it until after both modules have fully loaded.
Modules & Packaging;Functions & Scope
__all__ is a list of strings defined at module level specifying exactly which names are exported when a client does `from module import *`. Without __all__, `import *` imports all public names (those not starting with an underscore); with __all__ defined, only the listed names are imported, giving the module author explicit control over its public API surface.
# mymodule.py
__all__ = ['public_func', 'PublicClass']
def public_func(): pass
def _private_helper(): pass
class PublicClass: pass
# from mymodule import * only imports public_func and PublicClass
Real-world example
A utility module defines __all__ to explicitly exclude internal helper functions from wildcard imports, keeping the importing namespace clean and preventing accidental use of implementation details.
Modules & Packaging;Functions & Scope
Showing 1–10 of 15