Reference · module 18
Modules and shape
Everything this module explains, on one page.
import
Use code somebody else already wrote.
- import math brings in a whole module and you reach into it with a dot: math.sqrt(9). The name in front of the dot is the module, so it is always clear where a function came from.
- from math import sqrt brings in just the one name, and then it is sqrt(9) with no prefix. Shorter to write and harder to read later: three imports in and nobody knows whose sqrt this is.
- Imports go at the top of the file, all of them, before any other code. Not a rule Python enforces — it is a promise to whoever opens the file that the list of dependencies is in one place.
The mistake you are about to make
from math import *
import math
The star saves typing prefixes and brings everything at once. After three of them nobody knows where a name came from, and yours can be silently overwritten.
The standard library
Know what ships with Python before writing it yourself.
- Python arrives with a few hundred modules already installed. random.choice(items) picks one, random.randint(1, 6) rolls a die, and neither needs anything downloading.
- datetime.date.today() is today, and dates subtract: (a - b).days gives the number between them. Dates are one of the few things worth never writing yourself — months and leap years are a trap.
- So the habit worth having is to look first. Counting items, shuffling a list, reading JSON, working out a date — all of it is already there, tested by more people than will ever read your version.
The mistake you are about to make
working out a date difference by hand
datetime and (a - b).days
A gap between dates looks like arithmetic. Month lengths, leap years and clock changes are not, and all of it is already written and well tested.
Your own module
Split a program across files and import your own code.
- Any .py file is a module. Put a function in tools.py and from tools import clean brings it into the file next to it — your own code and the standard library are imported exactly the same way.
- The name is the file name without the .py, which is why a file called random.py in your folder breaks import random — yours is found first, and the error that follows names a module you did not write.
- Two files that import each other is a circular import, and it fails at load rather than at use. The fix is never a clever import — it is that one of the two should not have needed the other.
The mistake you are about to make
calling your file random.py
any name the standard library does not use
The file name is the module name. Calling yours random.py breaks import random for the whole folder, and the error points at a module you never wrote.
Run or import
Write a file that can be both a program and a module.
- Every file has a name in the variable __name__. Run it directly and that name is "__main__"; import it and the name is the module's own. One variable, two answers, depending on how it was reached.
- So if __name__ == "__main__": holds the code that should run only when the file IS the program. Under it goes the part that does something; above it, the functions somebody might want to import.
- Without the guard, importing your file runs it. Import a script that prints a report and you get the report — as a side effect of asking for one function out of it, which is nobody's intention.
The mistake you are about to make
top-level code sitting in the file
if __name__ == "__main__":
A script works fine while you run it. Import it for one function and the whole report happens as a side effect. Below the guard: doing. Above it: defining.
Writing it for a reader
Leave code somebody can change in six months.
- A name is the shortest documentation there is. total_price says what a number is; x says there is one. Python's own convention is lower case with underscores, and following it costs nothing.
- A function should do one thing, and the test is whether you can name it without an and. read_and_clean_and_save is three functions wearing one coat, and every one of them is harder to test inside it.
- A comment that says what the code says is noise; a comment that says WHY is the thing the code cannot say. `# retry twice because the API drops the first call after idle` is worth more than any restatement of the loop.
The mistake you are about to make
def read_and_clean_and_save():
three functions with three names
A name with "and" in it is an honest description and a diagnosis at once. A function does one thing, and the test is whether you can name it without the and.