Programming in Python · Lesson 13
Modules
Importing modules with import and from, creating your own modules, __name__ and main functions, docstrings, packages and relative imports, the math and random modules, and pip in Python.
Lesson purpose
Python comes with a huge library of code that other programmers have already written and tested, and programmers can package their own code for reuse. This lesson introduces modules: .py files of reusable code. Students learn how modules are organized, how to bring code in with import and from ... import, how to create their own modules, how to keep test code from running on import with if __name__ == "__main__":, how to document modules with docstrings and read documentation with help(), how to organize modules into folders with __init__.py and relative imports, and how to use the math and random modules and install third-party modules with pip.
For students who know C# and JavaScript: a Python module is roughly a C# namespace plus the file that holds it, and import math is like using System;. It is closest to JavaScript ES modules (import { factorial } from "./myMath.js"), except that in Python every top-level name in a module is importable without an export keyword. pip plays the role of NuGet or npm.
Learning objectives
By the end of the lesson, students should be able to:
- Explain what a module is and why using existing modules reduces errors and streamlines code.
- Describe where modules are stored and how they are organized, including nested modules.
- Import a module with
importand call its functions with dot notation. - Import specific items with
from ... import, import several items at once, and explain the*wildcard. - Import from a nested module.
- Create a module by placing a
.pyfile in the program’s folder. - Use a main function and
if __name__ == "__main__":so test code runs only when the module runs directly. - Write docstrings and read documentation with
help(). - Turn a folder into an importable package with
__init__.py, import from it, and use relative imports. - Use common functions from the
mathandrandommodules. - Install and uninstall third-party modules with
pip.
1. Storing code in modules
A library of previous knowledge
The functions and methods available in Python are vast, because other programmers have written code for everyone to use. Think of it as a big library: rather than writing every book yourself, you check out the ones you need.
A module is a file of Python code (a .py file). Some modules come with Python; others you download or write yourself. Using modules reduces errors (the code is already tested) and streamlines your programs.
Module structure
- A module is stored in the same folder as the current project or in a special folder of
.pysource files. Python keeps its standard modules in a known location, but your own modules can live anywhere Python can find them. - Because modules are separate files, you use a keyword to tell Python which modules (or parts of modules) to include, like telling the librarian which books to check out.
- Modules are organized by purpose. The
mathmodule holds math functions such asmath.pow(), so you do not have to write (and debug) them yourself. - Nested modules are modules stored inside other modules, like chapters in a book. The
pathmodule lives inside theosmodule and is referenced asos.path. Nested modules can be used on their own, like any other module.
2. Importing modules
import
Importing gives your program access to code in an external module:
import module_name
(The angle brackets in the book’s import <module_name> mark a placeholder; you type the real module name without them.)
After a plain import, you reference each item with the module name, a dot, and the item name:
import math
print(math.factorial(5)) # 120
Requiring the module name prevents naming conflicts. Even if you write your own factorial(), both versions stay available:
import math
def factorial(n):
print("My Special Factorial")
total = 1
for i in range(1, n + 1):
total *= i
return total
print(math.factorial(5)) # math module's version: 120
print(factorial(5)) # your version: prints the message, then 120
Clarifying note: the book says
importis “like copying all the code from a module into your code.” More precisely, Python runs the module once and gives your program a single name,math, that refers to it; the module’s contents stay in their own namespace. That separate namespace is exactly whymath.factorialand yourfactorialdo not collide.
from ... import
If you use an item often, typing the module name every time gets tedious. from ... import brings in only the items you name, and you use them without the prefix:
from module_name import function_name
from module_name import function1, function2
from math import factorial
print(factorial(5)) # 120
Importing only what you need keeps your namespace uncluttered and avoids accidentally replacing names you already defined.
The * wildcard
from module_name import *
This imports everything from the module, so you can use every item without the module name. from math import factorial and from math import * give the same result for the example above. The book suggests the wildcard when importing more than five items from the same module.
Clarifying note: Python’s official style guide (PEP 8) recommends avoiding wildcard imports in real programs. They make it unclear where a name came from and can silently overwrite your own names (or built-ins). If you need many items,
import mathandmath.prefixes are usually clearer.
Importing nested modules
Importing from a nested module works like importing from a top-level module. You can import the upper module (import os) or only the nested one you need:
from os import path # only the name path is added
print(path.exists("songs.txt"))
Clarifying note: the book says that importing only a nested module makes only its functions available. That is true for
from os import path. However,import os.pathalso importsositself and binds the nameos, soos.getcwd()would still work.
3. Creating modules
Getting started
To create a module, put your own .py file in the same folder as the program that uses it. Done.
Folder/
├── main.py
└── myMath.py
myMath.py is ordinary Python code, for example a variable pi and two functions, abs() and factorial(). Putting them in a module lets you and others reuse them in other programs:
# main.py
from myMath import pi, factorial
print("Pi:", pi)
print("Factorial of 7:", factorial(7))
The main function and __name__
While writing a module, you might add test statements at the bottom:
# myMath.py
pi = 3.14159
def abs(x):
if x < 0:
return -x
else:
return x
def factorial(n):
total = 1
for i in range(1, n + 1):
total *= i
return total
print("Testing math:")
print("Absolute value of -5:", abs(-5))
print("Absolute value of 5:", abs(5))
print("Value of pi:", pi)
print("Factorial of 5:", factorial(5))
Problem: importing a module runs all of its top-level code, including those print() statements. Running main.py now prints the whole test block before Pi: 3.14159 and Factorial of 7: 5040. The test printout should not be there.
Fix, step 1: put the test code inside a function so it runs only when called:
def test():
print("Testing math:")
print("Absolute value of -5:", abs(-5))
print("Absolute value of 5:", abs(5))
print("Value of pi:", pi)
print("Factorial of 5:", factorial(5))
Step 2: call it only when the module is run directly. Python creates a hidden variable, __name__, for every running file:
- When the file is imported,
__name__is the module’s name, such as"myMath". - When the file is run directly (for example, with F5 in IDLE),
__name__is"__main__".
if __name__ == "__main__":
test()
Now the tests run when you run myMath.py itself, but not when another program imports it. A function that holds a program’s main code this way is called a main function; the book’s example calls it test(), but it is frequently named main().
C#comparison: this is similar to a class library versus a console app’sstatic void Main(). A Python file can be both: a library when imported and a program when run.
Module documentation
Python’s modules document themselves. help() shows information about a module or function. Pass the function without parentheses, because you want help on the function itself, not to run it:
help(abs)
Output begins:
Help on built-in function abs in module builtins:
abs(x, /)
Return the absolute value of the argument.
Note: the book wraps this as
print(help(abs)).help()displays the text itself and returnsNone, so the extraprint()just adds a strayNoneat the end. Callhelp(abs)on its own.
You document your own modules with docstrings: strings in triple quotes. Their placement tells help() what they describe:
- A docstring at the very top of the
.pyfile documents the whole module. - A docstring as the first line inside a function documents that function.
"""myMath.py
Author: Dr. Elizabeth Matthews
A module containing some math functions and
an approximation of pi."""
pi = 3.14159
def abs(x):
"""abs(x)
Returns the absolute value of x."""
if x < 0:
return -x
else:
return x
def factorial(n):
"""factorial(n)
Returns the factorial of n."""
total = 1
for i in range(1, n + 1):
total *= i
return total
def test():
"""A test program for the module."""
print("Testing math:")
print("Absolute value of -5:", abs(-5))
print("Absolute value of 5:", abs(5))
print("Value of pi:", pi)
print("Factorial of 5:", factorial(5))
if __name__ == "__main__":
test()
import myMath followed by help(myMath) or help(myMath.factorial) displays these docstrings. C# programmers can compare docstrings to XML /// comments; JavaScript programmers to JSDoc /** */ comments.
Caution:
myMathdefines its ownabs(), which hides the built-inabs()inside that module (and in any program that doesfrom myMath import *). Reusing built-in names is legal but confusing; a name likeabsolute_value()is safer.
4. Creating nested modules
Folders as modules
When you have many modules, organize them into folders by category. To make a folder importable, place a special file named __init__.py (two underscores on each side of init) in it. The file can contain code but also works empty.
Folder/
├── main.py
└── myModules/
├── __init__.py
└── myMath.py
Chain the folder name and module name with a dot:
from myModules.myMath import abs
Module folders can be nested inside other module folders; the book says each needs its own __init__.py.
Terminology: Python calls a folder of modules a package. Since Python 3.3, a folder without
__init__.pycan often still be imported (a “namespace package”), but including__init__.pyis the standard, reliable practice and is required for some tools.
Relative imports
Inside a package, a module can import from a sibling module with a relative import. A plain import math or import myMath works as usual, but with from inside a module folder, a dot means “this package”:
# myModules/circle.py
from .myMath import pi
def area(radius):
return pi * radius * radius
def circumference(radius):
return 2 * pi * radius
.means the current package (folder)...means the package one level up,...two levels up, and so on, like relative file paths.
Examples from a file myModules/moduleA/example.py:
Import in example.py |
Reaches |
|---|---|
from .neighbor import * |
myModules/moduleA/neighbor.py |
from .subModule.subfile import * |
myModules/moduleA/subModule/subfile.py |
from ..upper import * |
myModules/upper.py |
from ..moduleB.other import * |
myModules/moduleB/other.py |
Caution: relative imports only work in a module that is imported as part of a package. Running such a file directly (for example,
python circle.py) fails withImportError: attempted relative import with no known parent package. Run the main program that imports it instead.
5. Useful modules
Built-ins and math
Some tools need no import at all: help(), abs(), sum(), print(), and the other built-in functions. For more advanced math, import the math module:
| Function | Description | Example |
|---|---|---|
math.factorial() |
Product of the integers from 1 to n (5 × 4 × 3 × 2 × 1) | math.factorial(5) → 120 |
math.pow() |
First parameter raised to the power of the second | math.pow(4, 3) → 64.0 |
math.sqrt() |
Square root | math.sqrt(16) → 4.0 |
math.cos() |
Cosine of an angle in radians | math.cos(1.5) |
math.pi |
The constant π | math.pi * radius * radius |
Note that math.pow() and math.sqrt() return floats. (The book calls a factorial a “multiplicative sum”; it is a product.)
random
The random module generates random values, useful for test data or a simple computer opponent in a game:
| Function | Description | Example |
|---|---|---|
random.randint(a, b) |
Random integer from a to b, including b |
random.randint(0, 10), random.randint(0, 1) |
random.choice(seq) |
One random item from a sequence such as a list | random.choice(["red", "blue", "green"]) |
random.shuffle(lst) |
Shuffles a list in place; returns nothing (None) |
n = [x for x in range(10)] then random.shuffle(n) |
random.sample(seq, k) |
A list of k unique random items |
random.sample(["red", "blue", "green", "orange", "yellow"], 2) |
Watch out: unlike
range(),randint()includes its upper bound. And becauseshuffle()changes the list and returnsNone,n = random.shuffle(n)destroys your list.
The pip command
Beyond the built-in modules, thousands of third-party modules can be downloaded. The pip command installs them from the command line (terminal or Command Prompt), not from inside a Python program:
python -m pip install module_name
-mtells Python to run thepipmodule.installtellspipto install the named module.pipalso installs any modules the package depends on. For example,matplotlib(graphing) requiresNumPy; installingmatplotlibpulls inNumPytoo. Lines that sayRequirement already satisfied:mean a dependency is already installed.
To remove a module, use uninstall; pip asks you to confirm with y or n:
python -m pip uninstall module_name
Tips: on macOS and Linux the command is often
python3 -m pip install ....pipis Python’s equivalent of NuGet forC#or npm for JavaScript.
Classroom application
- Import three ways. Print
math.sqrt(49)usingimport math,from math import sqrt, andfrom math import *; discuss which is clearest. - Name collision. Write your own
factorial()afterimport mathand show that both work; then switch tofrom math import *placed after your definition and observe which version wins. - Build a module. Create
myMath.pywithpi,abs(), andfactorial(), and amain.pythat imports from it. - Hide the tests. Add test prints to the bottom of
myMath.py, runmain.pyto see the unwanted output, then fix it withtest()andif __name__ == "__main__":. - Document it. Add module and function docstrings to
myMath.pyand read them withhelp(). - Package it. Move
myMath.pyinto amyModulesfolder with__init__.py, addcircle.pywith a relative import ofpi, and callarea()frommain.py. - Random practice. Simulate rolling two dice with
randint(), pick a random color withchoice(), and deal a hand of 5 cards withsample(). - pip demo. Install a small package (such as
emojiormatplotlib) withpython -m pip install, import it, and then uninstall it.
Common misconceptions
- “
import mathlets me callfactorial(5)directly.” A plainimportrequires the prefix:math.factorial(5). Usefrom math import factorialto drop it. - “Import statements only define things; nothing runs.” Importing runs all top-level code in the module, so put test code behind
if __name__ == "__main__":. - “
__name__is always"__main__".” It is"__main__"only for the file being run directly; an imported module’s__name__is its module name. - “Wildcard imports are best when importing many items.” They can hide where names come from and overwrite existing names; PEP 8 discourages them.
- “Pass the function call to
help().” Usehelp(abs), nothelp(abs()); the parentheses would call the function first. - “
pip installgoes inside my Python code.” It is a command-line command, not a Python statement. - “
random.randint(1, 6)works likerange(1, 6).”randintincludes 6;rangestops before 6. - “
numbers = random.shuffle(numbers)shuffles the list.”shuffle()returnsNone; call it on its own line. - “Relative imports work in any file.” They only work inside a package that is imported, not in a script run directly.
- “Naming my file
math.pyorrandom.pyis fine.” A file with the same name as a standard module can be imported instead of the real one and cause confusing errors.
Lesson summary
- Modules contain previously written, tested code. Python provides some modules as part of its installation; you can download modules from other programmers or create your own. Using modules reduces errors and streamlines code.
- Modules can be stored in the same folder as the main program or in a separate folder, which needs a file named
__init__.pyto be treated as a package of modules. - The keyword
importbrings in a module; withimportalone, items are referenced with the module name, as inmath.factorial(). Withfrom ... import, you can use just the item name, as infactorial(). - The
*wildcard withfromimports everything from a module; use it sparingly. - Importing runs a module’s code, so test code belongs in a main function called only when
__name__ == "__main__". - Docstrings are triple-quoted descriptions at the start of modules and functions;
help()displays them. - Relative imports work like relative paths:
.is the current package and..is the package above it. - The built-in
mathmodule provides math functions and constants; therandommodule provides random numbers, choices, shuffles, and samples. - Other modules are downloaded and installed (or uninstalled) with the
pipcommand, which also installs their dependencies.
Course Notes