ℹ️ Skipped - page is already crawled
| Filter | Status | Condition | Details |
|---|---|---|---|
| HTTP status | PASS | download_http_code = 200 | HTTP 200 |
| Age cutoff | PASS | download_stamp > now() - 6 MONTH | 0.3 months ago |
| History drop | PASS | isNull(history_drop_reason) | No drop reason |
| Spam/ban | PASS | fh_dont_index != 1 AND ml_spam_score = 0 | ml_spam_score=0 |
| Canonical | PASS | meta_canonical IS NULL OR = '' OR = src_unparsed | Not set |
| Property | Value |
|---|---|
| URL | https://joshcannon.me/2025/07/19/relative-imports.html |
| Last Crawled | 2026-04-02 16:18:52 (9 days ago) |
| First Indexed | 2025-07-22 14:31:47 (8 months ago) |
| HTTP Status Code | 200 |
| Meta Title | Python: Relative vs Absolute Imports |
| Meta Description | 9 out of 10 Pythonistas agree... |
| Meta Canonical | null |
| Boilerpipe Text | In the PyTexas Discord my fellow PyTexas organizer and friend, Mason Egger, asked:
Do you prefer absolute or relative imports for inter-module imports within applications?
Go ahead and
call me a Sith
because I deal in absolutes.
And here’s why.
Ways of running Python files
#
Python has more than a few ways of running a “Python file”:
python path/to/file.py
: Run the file at this path
python -m path.to.file
: Run the module found with this dotted name
python path/to
: Run the
__main__.py
file under this directory path
python -m path/to
: Run the module found with this dotted name, which this time would be the directory’s
__init__.py
python path/to/zipapp.zip
: Run this
zipapp
pytest
or any other installed script name: Run the script found at
<Python environment directory>/bin/<name>
, e.g.
.venv/bin/pytest
Ways of importing your fellow module
#
from . import sibling
: Imports
sibling
from under the same/parent directory this module is in
This first would try to import attribute
sibling
from
__init__.py
then try to import the module named
sibling
(either
sibling/__init__.py
or
sibling.py
)
from .sibling import boogers
: Same idea, but this time we need to load module
sibling
and attribute/submodule
boogers
from .. import uncle
: Imports
uncle
from under the grandparent directory (using similar rules)
from ..uncle import tickles
: (you get the jist)
from ... import great_aunt
: …
These are all examples of
relative
imports. What they import is
relative
to the module importing them.
(By the way, in case you needed one, here’s an example of an
absolute
import:
from pkgname.child import fun
)
Ways of running Python files which import their fellow modules
#
Given this
flat layout
project:
.
├── macaroni/
│ ├── __init__.py
│ ├── salad.py
│ └── and_/
│ ├── __init__.py
│ └── cheese.py
Contents / Invocation
python -m macaroni.and_.cheese
python macaroni/and_/cheese.py
from ..salad import dressing
🎉
💥
ImportError: attempted relative import with no known parent package
from macaroni.salad import dressing
🎉
🎉
Why is that?
#
Buried in the Python docs’ tutorials, in Chapter 6 “Modules”, Section 4 “Packages”, Subsection 2 “Intra-package References” (
6.4.2. here
),
there is this paragraph
1
:
Note that relative imports are based on the name of the current module’s package. Since the main module does not have a package, modules intended for use as the main module of a Python application must always use absolute imports.
When Python encounters a relative import,
it is relative to the current package
,
which for the “main module” (the module being invoked), doesn’t exist.
The bottom line
: Absolute imports work consistently irrespective of how your Python file is executed. Relative imports don’t give you that luxury.
The paragraph used to read differently, but it was also slightly incorrect so I suggested a change in
PR 136846
.
↩ |
| Markdown | [A Blog](https://joshcannon.me/)
- [Now](https://joshcannon.me/now)
# Python: Relative vs Absolute Imports
## 9 out of 10 Pythonistas agree...
Posted on July 19, 2025
In the PyTexas Discord my fellow PyTexas organizer and friend, Mason Egger, asked:
> Do you prefer absolute or relative imports for inter-module imports within applications?
Go ahead and [call me a Sith](https://youtu.be/wgpytjlW5wU?si=qoLqiNyuv0EJPpqD) because I deal in absolutes.
And here’s why.
# Ways of running Python files [\#](https://joshcannon.me/2025/07/19/relative-imports.html#ways-of-running-python-files)
Python has more than a few ways of running a “Python file”:
- `python path/to/file.py`: Run the file at this path
- `python -m path.to.file`: Run the module found with this dotted name
- `python path/to`: Run the `__main__.py` file under this directory path
- `python -m path/to`: Run the module found with this dotted name, which this time would be the directory’s `__init__.py`
- `python path/to/zipapp.zip`: Run this [zipapp](https://docs.python.org/3/library/zipapp.html)
- `pytest` or any other installed script name: Run the script found at `<Python environment directory>/bin/<name>`, e.g. `.venv/bin/pytest`
# Ways of importing your fellow module [\#](https://joshcannon.me/2025/07/19/relative-imports.html#ways-of-importing-your-fellow-module)
- `from . import sibling`: Imports `sibling` from under the same/parent directory this module is in
- This first would try to import attribute `sibling` from `__init__.py`
- then try to import the module named `sibling` (either `sibling/__init__.py` or `sibling.py`)
- `from .sibling import boogers`: Same idea, but this time we need to load module `sibling` and attribute/submodule `boogers`
- `from .. import uncle`: Imports `uncle` from under the grandparent directory (using similar rules)
- `from ..uncle import tickles`: (you get the jist)
- `from ... import great_aunt`: …
These are all examples of *relative* imports. What they import is *relative* to the module importing them.
(By the way, in case you needed one, here’s an example of an *absolute* import: `from pkgname.child import fun`)
# Ways of running Python files which import their fellow modules [\#](https://joshcannon.me/2025/07/19/relative-imports.html#ways-of-running-python-files-which-import-their-fellow-modules)
Given this [flat layout](https://packaging.python.org/en/latest/discussions/src-layout-vs-flat-layout/) project:
```
.
├── macaroni/
│ ├── __init__.py
│ ├── salad.py
│ └── and_/
│ ├── __init__.py
│ └── cheese.py
```
| Contents / Invocation | `python -m macaroni.and_.cheese` | `python macaroni/and_/cheese.py` |
|---|---|---|
| `from ..salad import dressing` | 🎉 | 💥 `ImportError: attempted relative import with no known parent package` |
| `from macaroni.salad import dressing` | 🎉 | 🎉 |
# Why is that? [\#](https://joshcannon.me/2025/07/19/relative-imports.html#why-is-that)
Buried in the Python docs’ tutorials, in Chapter 6 “Modules”, Section 4 “Packages”, Subsection 2 “Intra-package References” ([6\.4.2. here](https://docs.python.org/3/tutorial/modules.html#intra-package-references)), there is this paragraph [1](https://joshcannon.me/2025/07/19/relative-imports.html#fn:1):
> Note that relative imports are based on the name of the current module’s package. Since the main module does not have a package, modules intended for use as the main module of a Python application must always use absolute imports.
When Python encounters a relative import, [it is relative to the current package](https://docs.python.org/3/reference/import.html#package-relative-imports), which for the “main module” (the module being invoked), doesn’t exist.
**The bottom line**: Absolute imports work consistently irrespective of how your Python file is executed. Relative imports don’t give you that luxury.
***
1. The paragraph used to read differently, but it was also slightly incorrect so I suggested a change in [PR 136846](https://github.com/python/cpython/pull/136846). [↩](https://joshcannon.me/2025/07/19/relative-imports.html#fnref:1)
- [← Previous Post](https://joshcannon.me/2025/07/05/cogpinned-scripts.html "Using `cog` for pinned Single-File Python scripts")
- [Next Post →](https://joshcannon.me/2025/08/16/py-namespace-packages.html "Python Namespace Packages are a pain")
- [RSS](https://joshcannon.me/feed.xml "RSS")
- [Email me](mailto:joshdcannon@gmail.com "Email me")
- [GitHub](https://github.com/thejcannon "GitHub")
- [Mastodon](https://fosstodon.org/@thejcannon "Mastodon")
Josh Cannon • 2026
Powered by [Beautiful Jekyll](https://beautifuljekyll.com/) |
| Readable Markdown | In the PyTexas Discord my fellow PyTexas organizer and friend, Mason Egger, asked:
> Do you prefer absolute or relative imports for inter-module imports within applications?
Go ahead and [call me a Sith](https://youtu.be/wgpytjlW5wU?si=qoLqiNyuv0EJPpqD) because I deal in absolutes.
And here’s why.
## Ways of running Python files [\#](https://joshcannon.me/2025/07/19/relative-imports.html#ways-of-running-python-files)
Python has more than a few ways of running a “Python file”:
- `python path/to/file.py`: Run the file at this path
- `python -m path.to.file`: Run the module found with this dotted name
- `python path/to`: Run the `__main__.py` file under this directory path
- `python -m path/to`: Run the module found with this dotted name, which this time would be the directory’s `__init__.py`
- `python path/to/zipapp.zip`: Run this [zipapp](https://docs.python.org/3/library/zipapp.html)
- `pytest` or any other installed script name: Run the script found at `<Python environment directory>/bin/<name>`, e.g. `.venv/bin/pytest`
## Ways of importing your fellow module [\#](https://joshcannon.me/2025/07/19/relative-imports.html#ways-of-importing-your-fellow-module)
- `from . import sibling`: Imports `sibling` from under the same/parent directory this module is in
- This first would try to import attribute `sibling` from `__init__.py`
- then try to import the module named `sibling` (either `sibling/__init__.py` or `sibling.py`)
- `from .sibling import boogers`: Same idea, but this time we need to load module `sibling` and attribute/submodule `boogers`
- `from .. import uncle`: Imports `uncle` from under the grandparent directory (using similar rules)
- `from ..uncle import tickles`: (you get the jist)
- `from ... import great_aunt`: …
These are all examples of *relative* imports. What they import is *relative* to the module importing them.
(By the way, in case you needed one, here’s an example of an *absolute* import: `from pkgname.child import fun`)
## Ways of running Python files which import their fellow modules [\#](https://joshcannon.me/2025/07/19/relative-imports.html#ways-of-running-python-files-which-import-their-fellow-modules)
Given this [flat layout](https://packaging.python.org/en/latest/discussions/src-layout-vs-flat-layout/) project:
```
.
├── macaroni/
│ ├── __init__.py
│ ├── salad.py
│ └── and_/
│ ├── __init__.py
│ └── cheese.py
```
| Contents / Invocation | `python -m macaroni.and_.cheese` | `python macaroni/and_/cheese.py` |
|---|---|---|
| `from ..salad import dressing` | 🎉 | 💥 `ImportError: attempted relative import with no known parent package` |
| `from macaroni.salad import dressing` | 🎉 | 🎉 |
## Why is that? [\#](https://joshcannon.me/2025/07/19/relative-imports.html#why-is-that)
Buried in the Python docs’ tutorials, in Chapter 6 “Modules”, Section 4 “Packages”, Subsection 2 “Intra-package References” ([6\.4.2. here](https://docs.python.org/3/tutorial/modules.html#intra-package-references)), there is this paragraph [1](https://joshcannon.me/2025/07/19/relative-imports.html#fn:1):
> Note that relative imports are based on the name of the current module’s package. Since the main module does not have a package, modules intended for use as the main module of a Python application must always use absolute imports.
When Python encounters a relative import, [it is relative to the current package](https://docs.python.org/3/reference/import.html#package-relative-imports), which for the “main module” (the module being invoked), doesn’t exist.
**The bottom line**: Absolute imports work consistently irrespective of how your Python file is executed. Relative imports don’t give you that luxury.
***
1. The paragraph used to read differently, but it was also slightly incorrect so I suggested a change in [PR 136846](https://github.com/python/cpython/pull/136846). [↩](https://joshcannon.me/2025/07/19/relative-imports.html#fnref:1) |
| Shard | 80 (laksa) |
| Root Hash | 10028807919680690880 |
| Unparsed URL | me,joshcannon!/2025/07/19/relative-imports.html s443 |