Modules & Imports
Modules vs packages vs libraries
A module is a Python file. Any .py file can be imported and used by another one. As a project grows, splitting related functions and classes into their own files, then importing between them, keeps any one file from becoming unmanageable.
A package is a folder of related modules grouped together so they can be imported as one unit.
flowchart LR
subgraph package["package (folder)"]
direction LR
module1["module1.py"] ~~~ module2["module2.py"] ~~~ module3["module3.py"]
end
style module1 stroke:#3f6b52,stroke-width:2px
style module2 stroke:#3f6b52,stroke-width:2px
style module3 stroke:#3f6b52,stroke-width:2px
Fig. 10a — a package containing modules
Library is the informal umbrella term for either: a single module or a whole package — that's organized to be reused across projects. The Libraries page highlights a few common published libraries.
Importing modules
import
import makes a module's code available under its own name, so you call things through it with a . — random.randint(...), not just randint(...).
import random
print(random.randint(1, 10))
as
as gives the imported module a different name to call it by — handy for a long name you'd rather type shorter, or one that collides with something else in the file.
import random as rnd
print(rnd.randint(1, 10))
from
Specify a named piece that can be used directly: Naming the exact names you need is considered best practice, as it purposefully only imports the pieces you are using.
Packages
from package import module
flowchart LR
subgraph package["package (folder)"]
direction LR
module1["module1.py"] ~~~ module2["module2.py"] ~~~ module3["module3.py"]
end
style module1 stroke:#3f6b52,stroke-width:2px
style module2 stroke:#3f6b52,stroke-width:2px
style module3 stroke:#3f6b52,stroke-width:2px
Fig. 10b — example of a package's contents
from random import randint # specify with module with from
print(randint(1, 10))
Modules
from module import function/class/variable
flowchart LR
subgraph module["module.py"]
direction LR
function["function"] ~~~ class1["class"] ~~~ variable["variable"]
end
style module stroke:#3f6b52,stroke-width:2px
style function stroke:#4a7bb5,stroke-width:2px
style class1 stroke:#b5824a,stroke-width:2px
style variable stroke:#a3529c,stroke-width:2px
Fig. 10c — example of a module's contents
from snake_helpers import describe # describe is a function inside snake_helpers.py
print(describe("ball"))
Nested paths
from package.module import function/class/variable
flowchart LR
subgraph package["package (folder)"]
direction LR
subgraph module["module.py"]
direction LR
function["function"] ~~~ class1["class"] ~~~ variable["variable"]
end
end
style module stroke:#3f6b52,stroke-width:2px
style function stroke:#4a7bb5,stroke-width:2px
style class1 stroke:#b5824a,stroke-width:2px
style variable stroke:#a3529c,stroke-width:2px
Fig. 10d — example of a module inside a package
from os.path import join # os is a package, path is one of its modules
print(join("snakes", "ball_python.txt"))
Avoid from module import *
* is a wildcard standing in for "every name" — so from module import * pulls in every name from that module without saying which ones, so it's unclear later where a given name actually came from — randint on its own gives no hint it came from random rather than somewhere else in the file.
This isn't the same as plain import module: import module only puts the module itself in scope, so everything inside it still needs the . prefix (random.randint(...)). from module import * instead dumps every name from inside the module directly into scope, unprefixed — that's what makes it both convenient and risky.
from random import *
randint(1, 10) # works, but where did randint come from?
order of multiple imports
Imports go at the very top of the file, grouped in order: Python's own standard library first, then third-party packages, then your own local files — with a blank line between each group.
import random # standard library
import requests # third-party — installed separately
import snake_data # your own file
Creating your own module
Your own .py files import the same way — use the filename, without .py, as the module name.
# snake_helpers.py
def describe(species):
return f"a {species} python"
# main.py
import snake_helpers
print(snake_helpers.describe("ball"))
Avoid naming your own file after a library you use — your file named random.py shadows Python's own random module for anything else in that project. See the file naming rules for more.
The main guard
if __name__ == "__main__": controls what runs only when a file is run directly — not when it's imported into another file.
def describe(species):
return f"a {species} python"
if __name__ == "__main__":
print(describe("ball"))
Wrapping your "do the actual work" code in this check means another file can import yours — to reuse a function, say — without that main code running too.