Python offers three distinct ways to run a script or module, and each one affects sys.path
, __name__
, and import behavior in subtle but important ways.
Let’s break them down clearly:
bash
python path/to/script.py
✅ Most common for quick scripts
sys.path[0]
is set to the directory containing the script
__name__ == "__main__"
❌ Relative imports (like from .module import x
) do not work
bash
cd project_root/package
python utils.py
Fails if utils.py
uses relative imports.
-m
bash
python -m package.module
✅ Best for running code inside packages
sys.path[0]
is set to the directory containing the top-level package
__name__ == "package.module"
✅ Relative imports work correctly
bash
cd project_root
python -m package.utils
Works perfectly with from .logger import formatter
.
bash
python
Or:
bash
ipython
✅ Great for experimentation
sys.path[0]
is set to the current working directory (CWD)
__name__ == "__main__"
for any code typed or run
✅ Imports work if modules are in the CWD or PYTHONPATH
bash
cd project_root/package
python
>>> import utils # works if utils.py is in CWD
Method | sys.path[0] |
__name__ |
Relative Imports Work? |
---|---|---|---|
python script.py |
Directory of script | "__main__" |
❌ No |
python -m package.mod |
Directory of top-level pkg | "package.mod" |
✅ Yes |
Interactive / REPL | Current working directory | "__main__" |
✅ Sometimes |
You can make a module runnable both ways by adding:
python
if __name__ == "__main__":
# CLI entry point or test logic
And using python -m package.module
for proper relative imports.