Background: Packages were introduced in Python to structure large codebases and to facilitate code reuse. They allow projects to be divided into logical modules, making it easier to maintain and import necessary functionality.
Issue: Incorrect understanding of the structure of packages can lead to import errors, name conflicts, and script execution errors. It's essential to know the difference between packages and modules and the rules for working with relative and absolute imports.
Solution:
A package is any directory containing an __init__.py file (empty or with initialization code). Packages can contain other packages and modules. Example structure:
project/
├── mypackage/
│ ├── __init__.py
│ ├── mod1.py
│ └── subpackage/
│ ├── __init__.py
│ └── mod2.py
└── script.py
To import, we use a relative (from .subpackage import mod2) or absolute path (from mypackage.subpackage import mod2). Absolute imports are preferable for larger projects.
Key Features:
__init__.pyDoes __init__.py need to be present in every folder we want to make a package?
Yes, for Python versions below 3.3; in modern versions of Python (3.3+), there are "implicit" namespace packages, but for full compatibility, the file is still recommended.
What happens if you import a package instead of a module?
Only the code in __init__.py of that package will run.
What is the difference between the imports “from . import mod1” and “import mod1”?
from . import mod1 (relative import) works only within the package, while absolute import searches for the module in sys.path, which can lead to name conflicts.
__init__.py filesNegative Case: Modules with the same names in different subfolders without using absolute imports. One module is accessed by a different package than intended. Pros:
Positive Case:
Explicitly defining absolute imports, correct folder structure, and having __init__.py.
Pros: