Study guide
2.3 Package Hierarchy and Navigation
OpenEDG PCAP — Certified Associate in Python Programming Exam
Track your progress as you read
Finished sections get a check mark.
1 Chapter 1: The PCAP-31-03 Exam Blueprint and Test-Day Logistics
1.1 The PCAP-31-03 Blueprint, Scoring, and Exam-Day Logistics
2 Chapter 2: Modules, Packages, and the Standard Library
2.1 Module Imports and Namespace Mechanics 2.2 Module Construction and Execution 2.3 Package Hierarchy and Navigation 2.4 Standard Library Modules and Pip
3 Chapter 3: Exceptions and Error Handling
3.1 Exception Control Flow and Syntax 3.2 The Built-in Exception Hierarchy 3.3 Raising Exceptions and Assertions 3.4 Custom Exceptions and Exception Chaining
4 Chapter 4: Strings, Encodings, and Text Processing
4.1 Character Encodings and String Immutability 4.2 String Indexing, Slicing, and Comparison 4.3 String Inspection and Classification Methods 4.4 String Transformation and Formatting Methods 4.5 Iterating, Sorting, and Comparing Strings Against Other Types
5 Chapter 5: Object-Oriented Programming Fundamentals
5.1 Classes, Instances, and Attributes 5.2 Encapsulation, Privacy, and Name Mangling 5.3 Dunder Methods and Object Lifecycle 5.4 Discovering Class Structure: __name__, __module__, __bases__, and Identity
6 Chapter 6: Advanced OOP, Inheritance, and Metaprogramming
6.1 Single Inheritance, Method Overriding, and Polymorphism 6.2 Multiple Inheritance and Method Resolution Order (MRO) 6.3 Class Methods, Static Methods, and Properties
7 Chapter 7: Functional Python, Comprehensions, and Closures
7.1 List, Dictionary, and Set Comprehensions 7.2 Lambda Expressions and Higher-Order Functions 7.3 Variable Scopes, the LEGB Rule, and Closures
8 Chapter 8: Iterators, Generators, and File I/O
8.1 Iterators and the Iteration Protocol 8.2 Generator Functions and Generator Expressions 8.3 File Input/Output and Context Managers 8.4 Predefined Streams, Handles vs. Streams, and errno Diagnostics
2.3 Package Hierarchy and Navigation
Key Takeaways Explain This Topic AI
A Python package is a directory containing Python modules and an __init__.py file that marks the directory as an importable package.
The __init__.py file initializes the package namespace, executes upon first import of the package or any sub-entity, and can expose convenient package-level APIs.
The module search path is maintained as a list in sys.path and searched in strict order: the script directory, PYTHONPATH , standard library, and site-packages .
Relative imports use leading dot syntax ( . for the current package, .. for the parent package) and are only valid within package modules, not standalone executable scripts.
Dotted notation ( import alpha.beta.gamma ) enables navigation of deeply nested subpackages and distinct module hierarchies.
Last updated: August 2026
Package Hierarchy and Navigation
As applications grow to encompass dozens or hundreds of modules, placing all files in a single flat directory becomes unmanageable. Python addresses this complexity through packages —a hierarchical directory structuring mechanism that groups related modules under common namespaces.
1. What is a Python Package?
In Python, a package is essentially a filesystem directory that contains one or more module files ( .py ) and typically a special initialization file named __init__.py .
Just as modules prevent global variable collisions between functions, packages prevent module name collisions between different libraries (e.g., your project's utils.py will not conflict with a third-party library's utils.py because they reside in different package namespaces: myproject.utils vs requests.utils ). ecommerce/ # Top-level Package
- ├── __init__.py # Package initialization file
- ├── inventory/ # Subpackage
- │ ├── __init__.py
- │ └── warehouse.py # Module: ecommerce.inventory.warehouse
- ├── orders/ # Subpackage
- │ ├── __init__.py
- │ └── processing.py # Module: ecommerce.orders.processing
- └── payments/ # Subpackage
- ├── __init__.py
- └── gateway.py # Module: ecommerce.payments.gateway
- The Role of __init__.py
The presence of __init__.py serves several vital functions in Python:
Package Identifier : Historically required to mark a directory as a regular Python package rather than a plain directory (since Python 3.3, PEP 420 introduced implicit namespace packages, but __init__.py remains standard for regular packages).
Initialization Code : Whenever any module inside the package is imported, the package's __init__.py file is executed automatically first.
Public API Aggregation : __init__.py can import key functions and classes from submodules so callers do not need to know the internal directory structure.
Wildcard Export Control : Defining __all__ inside __init__.py dictates which submodules are imported when a user runs from package import * . # File: ecommerce/__init__.py
print("[ecommerce] Initializing ecommerce package")
- # Expose subpackage shortcuts directly at the top level
- from .payments.gateway import process_credit_card
- from .inventory.warehouse import check_stock
- __all__ = ['process_credit_card', 'check_stock']
- With this __init__.py in place, consumers can simply write: import ecommerce
- ecommerce.process_credit_card(150.00)
- 2. Package Navigation and Dotted Notation
Python uses dotted notation ( pkg.subpkg.module ) to traverse nested package hierarchies.
- Syntax Variations for Packages # 1. Full Module Import
- import ecommerce.payments.gateway
- ecommerce.payments.gateway.process_credit_card(99.95)
- # 2. Module Import with Alias
- import ecommerce.payments.gateway as gw
- gw.process_credit_card(99.95)
- # 3. Submodule Import from Package
- from ecommerce.payments import gateway
- gateway.process_credit_card(99.95)
- # 4. Direct Entity Import
- from ecommerce.payments.gateway import process_credit_card
- process_credit_card(99.95)
- 3. The Module Search Path: sys.path
How does Python locate modules and packages when an import statement is executed? It queries the search path stored in sys.path —a standard Python list of filesystem directory paths.
Strict Search Resolution Order
When an import statement is evaluated, Python searches the directories listed in sys.path in strict sequential order from index 0 upwards:
sys.path[0] (Script Directory) : The directory containing the top-level script used to invoke the interpreter (or current working directory if running in an interactive REPL).
PYTHONPATH Directories : Any directory paths defined in the operating system environment variable PYTHONPATH .
Standard Library Directories : The official installation directory containing Python's built-in and standard library modules (e.g., math , os , sys , random ).
Site-Packages Directories : The third-party installation directory where pip installs external packages.
If the target module or package is not found in any of these directories, Python raises a ModuleNotFoundError . import sys
print("=== Python Module Search Path ===")
for idx, directory in enumerate(sys.path):
- print(f"[{idx}] {directory}")
- Modifying sys.path Dynamically at Runtime
Because sys.path is a mutable Python list , programs can dynamically modify the search path at runtime before invoking import : import sys
- # Add a custom directory to the end of the search path
- sys.path.append('/opt/shared_libraries')
- # Or insert at index 0 to give custom modules highest priority
- sys.path.insert(0, '/home/user/custom_plugins')
- # Now modules inside /home/user/custom_plugins can be imported
- import custom_auth
- 4. Absolute vs. Relative Imports
Within packages, Python supports two distinct import strategies: absolute imports and relative imports.
Absolute Imports
An absolute import specifies the complete path from the project's root package or an entry in sys.path : # Inside ecommerce/orders/processing.py
- from ecommerce.payments.gateway import process_credit_card
- from ecommerce.inventory.warehouse import check_stock
Pros : Explicit, unambiguous, and recommended by PEP 8.
Cons : Renaming the top-level package requires updating import statements throughout all files.
Relative Imports
Relative imports specify the target module relative to the location of the current module within the package hierarchy using leading dot ( . ) syntax:
Single dot ( . ) : The current package directory.
Double dot ( .. ) : The parent package directory.
Triple dot ( ... ) : The grandparent package directory. # Inside ecommerce/orders/processing.py (located in ecommerce/orders/)
- # Import from the SAME subpackage (ecommerce/orders/)
- from . import invoice_generator
- # Import from a SIBLING subpackage (ecommerce/payments/)
- from ..payments.gateway import process_credit_card
- # Import from another SIBLING subpackage (ecommerce/inventory/)
- from ..inventory.warehouse import check_stock
- The Relative Import Execution Constraint
CRITICAL PCAP EXAM TRAP: Relative imports rely strictly on the module's __name__ and __package__ attributes to resolve parent hierarchy.
If you attempt to run a submodule containing relative imports directly as a script (e.g., python ecommerce/orders/processing.py ), Python assigns __name__ = '__main__' and leaves __package__ = None .
When Python encounters from ..payments import gateway , it cannot determine the parent package and immediately raises: ImportError: attempted relative import with no known parent package
To execute a package submodule as an entry point, use Python's -m (module) flag from the root project directory: python -m ecommerce.orders.processing