21 · Modules: import, from, as
Every .py file is a module. Master import, from … import, aliases, and the __name__ guard that keeps scripts safe to reuse.
A **module** is any `.py` file. `import math` gives you the module object; `from math import sqrt` pulls a specific name directly into your namespace; `import numpy as np` binds a short alias. Python searches `sys.path` — an ordered list of directories — to find each module.
Without this:
Without modules, every reusable function must be copy-pasted into every script that needs it — one typo in one copy causes a silent divergence. Modules let you write code once and import it everywhere.
Every .py file is a module. When Python executes import math, it searches sys.path (a list of directories — the current directory, installed-packages paths, and stdlib paths), finds math, executes it once, caches the result in sys.modules, and binds the name math in your namespace. from math import sqrt, pi imports specific names directly — you skip the math. prefix. import numpy as np binds the module to the shorter name np. The if __name__ == "__main__": guard at the bottom of a file lets you write code that runs only when the file is executed directly — never when it is imported as a module by another script.
Python (in browser)
`import math` keeps every name inside the `math` namespace. Two imported modules can both have a `log` function and they'll never clash because you access them as `math.log` and `cmath.log`.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`from math import sqrt, pi` drops those two names straight into your local namespace. Notice the last line would fail — once you use `from math import ...` you no longer have the `math` prefix available unless you also wrote `import math`.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`import math as m` binds the module to `m`. The aliases `np`, `pd`, and `plt` are community conventions strong enough that linters will warn you if you deviate from them.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Without the `if __name__ == "__main__":` guard, importing `compute_loss` from `train.py` would also kick off a training run — a common source of surprise. The guard makes the file safe to import while still runnable as a script.
What does writing `import numpy as np` accomplish?
- `import math` — module object in namespace; access via `math.sqrt`. `from math import sqrt` — name directly in scope. `import numpy as np` — full module, short alias.
- Python finds modules by searching `sys.path` in order: current directory, then installed packages, then stdlib. Once found, the module is cached in `sys.modules` — subsequent imports are free.
- Add `if __name__ == "__main__":` at the bottom of any script you also want to be importable. It prevents the script's top-level code from running on import.
Every ML script opens with `import numpy as np; import pandas as pd; import torch`. The `as np` alias is so universal that breaking it would confuse every reader. The `if __name__ == "__main__":` guard lets `train.py` be both a standalone training script and an importable module so a hyperparameter-sweep orchestrator can call `from train import compute_loss` without triggering a full training run.
If you remove it: Without module imports, every ML project would need to bundle a copy of numpy, pandas, and scikit-learn directly in each script — or paste the source. Modules make the entire Python ecosystem available to any file with a single line.