One Program, Several Files
One file gets long. Python lets a program live in several files, and each file is a module: a .py file whose functions and names other files can borrow. The word that does the borrowing is import, and you have been using it since Chapter 2 on modules that came with Python. This page uses it on your own code.
Think of a kitchen with labelled drawers. import tips opens the drawer called tips; tips.calculate_tip takes out the one tool you need from it. Everything else in the drawer stays where it is until you ask for it.
A Module Is a .py File
Move the tip calculation from Chapter 5 into a file of its own called tips.py, in your python-course folder. It holds one function and nothing else.
def calculate_tip(bill, percent): """Return the tip for a bill at the given percentage.""" return bill * percent / 100
A second file, main.py, in the same folder, imports it. After import tips, the function is reached through the module's name and a dot, tips.calculate_tip, just as csv.DictReader belonged to the csv module in Chapter 7.
import tips print(tips.calculate_tip(40, 15))
6.0
from ... import
The other form brings one name straight in, so it can be used without the module's name in front: from tips import calculate_tip. It is shorter to use; the dotted form makes it obvious where a name came from. Both are common. For the standard library's tools this book has used the short form, as in from decimal import Decimal, and the dotted form where the module name adds meaning, as in csv.DictReader.
The Line That Makes a File Both Runnable and Importable
Now suppose tips.py also has a little demonstration at the bottom, so you can run it on its own. The problem: importing a module runs its whole file, top to bottom, once. So running main.py now prints the demonstration as well, which is not what main.py wanted.
def calculate_tip(bill, percent): """Return the tip for a bill at the given percentage.""" return bill * percent / 100 print("Demo: a tip on 40 at 15 percent is", calculate_tip(40, 15))
Demo: a tip on 40 at 15 percent is 6.0 6.0
The fix is one line that you will see at the bottom of countless Python files. Every module has a name, __name__, with two underscores on each side. When a file is run directly, its __name__ is the text __main__; when it is imported, its __name__ is the module's own name. So the question "was this file run directly?" is written if __name__ == "__main__":, and the demonstration goes inside it.
def calculate_tip(bill, percent): """Return the tip for a bill at the given percentage.""" return bill * percent / 100 if __name__ == "__main__": print("Demo: a tip on 40 at 15 percent is", calculate_tip(40, 15))
6.0
Run tips.py directly and the demonstration still appears; import it and it stays quiet. This is also the line Chapter 5 promised for the call to main(): from now on, a program's last lines are if __name__ == "__main__": and, indented under it, main().
The double underscores mark names that Python sets up for every module by itself. Chapter 7 used another one: __file__, which holds the path of the file the code is in. That is why Path(__file__).parent is the folder a script lives in, wherever the terminal happens to be.
A Package Is a Folder of Modules
When a program has many modules, related ones go in a folder, and the folder becomes a package. You import from it with a dot: from shop import tips finds tips.py inside a folder called shop. That is enough to recognise packages when you meet them; building and publishing your own is beyond this book.
Do Not Borrow a Standard Module's Name
Name your own file csv.py and import csv finds your file instead of Python's module, because the folder that holds the script you ran is searched before the standard library. (At the interactive prompt it is the terminal's current folder.) Everything that uses the real module then breaks. Python 3.15 recognises this situation and says so, at the end of an otherwise puzzling message: consider renaming csv.py, since it has the same name as the standard library module.
import csv with open("statement.csv", encoding="utf-8", newline="") as f: for row in csv.DictReader(f): print(row)
Traceback (most recent call last):
File "/Users/you/python-course/csv.py", line 1, in <module>
import csv
File "/Users/you/python-course/csv.py", line 4, in <module>
for row in csv.DictReader(f):
^^^^^^^^^^^^^^
AttributeError: module 'csv' has no attribute 'DictReader' (consider renaming '/Users/you/python-course/csv.py' since it has the same name as the standard library module named 'csv' and prevents importing that standard library module)
If you tried this, delete or rename your csv.py before going on; every later program that imports csv would find it first.
- "import copies the other file's code into mine." It runs the module once and gives you access to its names through the module's name.
- "
if __name__ == "__main__"is magic." It is an ordinary question: was this file run directly, or imported? - "I can name my files anything I like." Not after a module you also import. A file called csv.py hides the real csv module.
- Splitting code into modules is how programs grow past a few hundred lines without becoming unreadable.
- Understanding import explains the first lines of every Python file you will ever read.
Knowledge Check
What does import tips give you access to?
- The names defined in tips.py, as tips.something
- A copy of tips.py pasted into the current file, line by line
- Only the very first function that is written in tips.py
- The folder that tips.py happens to be stored in
Why add if __name__ == "__main__": at the bottom of a module?
- To make the module load faster whenever another file imports it
- Because Python refuses to import files without it
- So its demo runs when run directly, not when imported
- To stop other files from importing it at all
What is __name__ inside a module that has been imported?
- Always the text __main__, whatever happens
- The name of the file that did the importing
- The module's own name, such as tips
- Empty, until the module is run on its own
You save a script as csv.py and import csv breaks. Why?
- The csv module is not installed with Python
- Python cannot import a module that reads files
- A script and a module are not allowed to live in the same folder
- Your csv.py is found first and hides Python's csv
You got correct