Python Modules & the Standard Library
In software development, a library is like a toolbox for developers. Instead of implementing every part of your code from scratch, a library gives you pre-written, reusable code, such as functions, classes, and data structures, that you can use in your projects. In Python, each file of such code is called a module.
The Standard Library
Section titled “The Standard Library”Python comes with an extensive standard library: a large collection of built-in modules. They are standardized, well-vetted solutions to many of the problems and tasks you will face daily as a programmer, such as:
- Interacting with the operating system
- Working with files
- Networking
- Working with date and time
- Performing mathematical operations
- Using regular expressions
- Testing and debugging your code
- And much more
Some of the most popular modules:
| Module | Purpose |
|---|---|
math | Helpful functions for more complex mathematical operations |
random | Generating random numbers and making random choices |
re | Working with regular expressions |
datetime | Working with dates and times |
No installation is needed. You only have to import a module to use it.
At a Glance
Section titled “At a Glance”| Task | Syntax | Example |
|---|---|---|
| Import a module | import module | import math |
| Use its contents | module.name | math.sqrt(36) |
| Give it an alias | import module as alias | import math as m |
| Import specific names | from module import a, b | from math import sin, cos |
| Alias a specific name | from module import a as x | from math import sqrt as root |
| Import everything (avoid) | from module import * | from math import * |
| Explore a module | dir(module), help(module) | help(math.sqrt) |
| Run code only when executed directly | if __name__ == '__main__': | See the idiom |
Importing a Module
Section titled “Importing a Module”Use an import statement to access the variables, constants, functions, and classes defined in a module. Import statements are generally written at the top of the file.
import module_nameFor example, to import the math module:
import mathThen call a function from the module with dot notation: the module name, a dot, then the name.
import math
print(math.sqrt(36)) # 6.0Here sqrt is an abbreviation of “square root”. Inside the parentheses you pass any necessary arguments. In this case, the number you want the square root of.
Importing with an Alias
Section titled “Importing with an Alias”To import a module under a different name, add as followed by the alias at the end of the statement.
import module_name as module_aliasAliases are often used to shorten long module names or to avoid naming conflicts.
import math as m
print(m.sqrt(36)) # 6.0, access elements through the aliasImporting Specific Names
Section titled “Importing Specific Names”Sometimes you do not need everything from a module, only one or two functions or classes. In that case, start the statement with from, name the module, then import the names you want.
from module_name import name1, name2You can then use those names without the module prefix. To give them aliases, use as after each name:
from module_name import name1 as alias1, name2 as alias2For example, to import only the radians, sin, and cos functions from math:
from math import radians, sin, cosNow you can call these functions directly, without math as a prefix.
A Worked Example
Section titled “A Worked Example”To find the sine and cosine of an angle given in degrees, convert it to radians with radians(), then pass the result to sin() and cos():
from math import radians, sin, cos
angle_degrees = 40angle_radians = radians(angle_degrees)
sine_value = sin(angle_radians)cos_value = cos(angle_radians)
print(sine_value) # 0.6427876096865393print(cos_value) # 0.766044443118978Notice that the functions are called directly, without the name of the module as a prefix. That is a consequence of importing them with this alternative syntax.
Watch for Naming Conflicts
Section titled “Watch for Naming Conflicts”This style is convenient, but it can cause naming conflicts if your script already defines a function or variable with the same name. The later definition silently replaces the earlier one.
from math import sqrt
def sqrt(x): # Replaces the imported sqrt return 'my own version'
print(sqrt(36)) # 'my own version'An alias avoids the clash:
from math import sqrt as math_sqrt
def sqrt(x): return 'my own version'
print(math_sqrt(36)) # 6.0print(sqrt(36)) # 'my own version'Wildcard Imports
Section titled “Wildcard Imports”An import ending with an asterisk tells Python to import everything from the module, with no module prefix needed.
from module_name import *For example, after importing math this way, you can call any function defined in it without the prefix:
from math import *
print(sqrt(36)) # 6.0print(pow(5, 2)) # 25.0print(exp(1)) # 2.718281828459045Choosing an Import Style
Section titled “Choosing an Import Style”import math
math.sqrt(36)math.pi- Every use shows where the name comes from
- No naming conflicts
- Slightly longer to type
The safest default.
from math import sqrt, pi
sqrt(36)pi- Short and readable
- Good when you use a few names often
- Can clash with your own names
Good for a small, known set of names.
import math as m
m.sqrt(36)- Shortens long module names
- Resolves clashes between two modules
- Follow community conventions where they exist
Common with third-party packages: import numpy as np, import pandas as pd.
from math import *
sqrt(36)- Pollutes your namespace
- Hides where names come from
- Can silently replace built-ins
Avoid it in real code.
What You Can Import
Section titled “What You Can Import”Import statements work exactly the same for functions, classes, constants, variables, and any other element defined in a module.
A Constant
Section titled “A Constant”import math
print(math.pi) # 3.141592653589793print(math.e) # 2.718281828459045A Class
Section titled “A Class”Here is a class from the datetime module. It creates a date object that represents July 15, 1959, assigns it to a variable, and accesses the day, month, and year individually with dot notation:
import datetime
birthday = datetime.date(1959, 7, 15)print(birthday.day) # 15print(birthday.month) # 7print(birthday.year) # 1959The same thing with from:
from datetime import date
birthday = date(1959, 7, 15)print(birthday) # 1959-07-15Exploring a Module
Section titled “Exploring a Module”You can find more information about a module’s content in the official Python documentation for that module. You can also explore from inside Python:
import math
print('sqrt' in dir(math)) # True, dir() lists every name in the moduleprint(math.__name__) # 'math'help(math.sqrt) # Prints the documentation for sqrtA Tour of the Standard Library
Section titled “A Tour of the Standard Library”| Module | Use it for |
|---|---|
math | Square roots, trigonometry, logarithms, constants |
random | Random numbers, shuffling, sampling |
datetime | Dates, times, differences between dates |
re | Regular expressions (pattern matching in text) |
os, pathlib | Operating system interaction, file paths |
sys | The interpreter: command-line arguments, exiting, module paths |
json, csv | Reading and writing common data formats |
collections | Counter, defaultdict, deque |
itertools, functools | Advanced iteration and function tools |
statistics | Mean, median, standard deviation |
time | Pausing, measuring elapsed time |
logging | Recording diagnostic messages |
unittest | Writing automated tests |
urllib, http, socket | Networking |
sqlite3 | A lightweight built-in database |
argparse | Command-line interfaces |
dataclasses, enum, typing | Structuring and annotating your code |
import math
print(math.sqrt(36)) # 6.0print(math.ceil(3.2)) # 4, round upprint(math.floor(3.7)) # 3, round downprint(math.gcd(12, 18)) # 6, greatest common divisorprint(math.factorial(5)) # 120print(math.hypot(3, 4)) # 5.0, length of the hypotenuseprint(math.isclose(0.1 + 0.2, 0.3)) # True, safe float comparisonrandom
Section titled “random”import random
print(random.random()) # A float from 0.0 up to (not including) 1.0print(random.randint(1, 6)) # An integer from 1 to 6, both ends includedprint(random.choice(['red', 'green', 'blue'])) # One random item
cards = [1, 2, 3, 4, 5]random.shuffle(cards) # Shuffles the list in placeprint(random.sample(cards, 2)) # Two unique items, as a new list
random.seed(42) # Same seed gives the same sequence (reproducible runs)datetime
Section titled “datetime”from datetime import date, datetime, timedelta
birthday = date(1959, 7, 15)print(birthday.strftime('%B %d, %Y')) # July 15, 1959print(birthday.strftime('%A')) # Wednesday
print(date(2024, 1, 31) + timedelta(days=1)) # 2024-02-01print((date(2025, 1, 1) - date(2024, 1, 1)).days) # 366
parsed = datetime.strptime('2024-03-15', '%Y-%m-%d')print(parsed) # 2024-03-15 00:00:00
print(datetime.now()) # The current date and timeimport re
print(re.findall(r'\d+', 'a1b22c333')) # ['1', '22', '333']print(re.sub(r'\s+', ' ', 'a b c')) # 'a b c'
match = re.search(r'(\w+)@(\w+)\.com', 'Write to ann@site.com today')print(match.group(1)) # 'ann'print(match.group(2)) # 'site'pathlib, os, and sys
Section titled “pathlib, os, and sys”from pathlib import Pathimport osimport sys
path = Path('data') / 'report.txt' # Builds a path with the right separatorprint(path.suffix) # '.txt'print(path.exists()) # True or False
print(os.getcwd()) # The current working directoryprint(os.path.join('data', 'x.txt')) # 'data/x.txt' (or 'data\\x.txt' on Windows)
print(sys.version) # The Python versionprint(sys.argv) # Command-line arguments as a list of stringsjson, statistics, and time
Section titled “json, statistics, and time”import jsonimport statisticsimport time
text = json.dumps({'name': 'Ann', 'age': 31})print(text) # '{"name": "Ann", "age": 31}'print(json.loads(text)['name']) # 'Ann'
print(statistics.mean([1, 2, 3, 4])) # 2.5print(statistics.median([1, 3, 2])) # 2
start = time.perf_counter()time.sleep(0.1) # Pause for a tenth of a secondprint(time.perf_counter() - start) # Elapsed seconds, about 0.1Writing Your Own Modules
Section titled “Writing Your Own Modules”Any Python file is a module. Its name is the filename without .py.
PI = 3.14159
def circle_area(radius): return PI * radius ** 2import shapesfrom shapes import circle_area
print(shapes.PI) # 3.14159print(circle_area(2)) # 12.56636Both files must be in the same folder (or the folder must be on Python’s search path).
Packages
Section titled “Packages”A package is a folder of modules. Adding an __init__.py file marks the folder as a package (it can be empty).
project/├── main.py└── utils/ ├── __init__.py ├── text.py └── numbers.pyfrom utils.text import slugify # A name from utils/text.pyimport utils.numbers as nums # The whole module, with an alias
import os.path # The standard library has packages toofrom os import path # Same module, imported differentlyInside a package, modules can import their siblings with relative imports:
from . import numbers # The sibling module numbers.pyfrom .numbers import clamp # A name from that siblingHow Python Finds and Loads Modules
Section titled “How Python Finds and Loads Modules”When you write import something, Python looks for it in this order:
-
The module cache. If the module was already imported, Python reuses it from
sys.modules. -
Built-in modules. Modules compiled into Python itself, such as
sys. -
The search path (
sys.path). A list of folders checked in order: the folder of the running script, any folders in thePYTHONPATHenvironment variable, the standard library, and installed third-party packages (site-packages).
import sys
for folder in sys.path: print(folder) # The first entry is the folder of your scriptModules Run Once
Section titled “Modules Run Once”The code in a module executes the first time it is imported. Later imports reuse the loaded module without running it again.
print('counter_module is loading')VALUE = 1import sysimport counter_module # Prints: counter_module is loadingimport counter_module # Prints nothing, already loaded
print('counter_module' in sys.modules) # TrueTo force a re-run during development, use importlib.reload(counter_module).
Do Not Name Your File Like a Standard Module
Section titled “Do Not Name Your File Like a Standard Module”Because Python searches your script’s folder first, a file called random.py or math.py hides the real module.
import random
print(random.randint(1, 6))# AttributeError: partially initialized module 'random' has no attribute 'randint'# (most likely due to a circular import)Rename your file (for example dice.py) and delete any leftover __pycache__ folder.
Third-Party Packages
Section titled “Third-Party Packages”Beyond the standard library, thousands of packages written by the community live on the Python Package Index (PyPI). Install them with pip, then import them like any other module.
python -m pip install requestspython -m pip listimport requests
response = requests.get('https://example.com')print(response.status_code)The if __name__ == '__main__' Idiom
Section titled “The if __name__ == '__main__' Idiom”Now that you know more about modules, there is one very important idiom in Python scripts that is closely related:
if __name__ == '__main__': # Code pass__name__ is a special built-in variable in Python.
- When a Python file is executed directly, Python sets
__name__to the string"__main__". - When the file is imported as a module into another script,
__name__is set to the name of that module (usually the filename without the.pyextension).
| How the file is used | Value of __name__ |
|---|---|
python greeter.py | '__main__' |
import greeter from another file | 'greeter' |
python -m greeter | '__main__' |
That is why you will often find this conditional in Python scripts. It contains the code you want to run only if the script is running as the main program. If the script is imported as a module, the code inside the block does not run.
def greet(name): return f'Hello, {name}!'
print('greeter: __name__ is', __name__)
if __name__ == '__main__': print(greet('Ann'))$ python greeter.pygreeter: __name__ is __main__Hello, Ann!The main block runs.
import greeter
print(greeter.greet('Bob'))$ python other.pygreeter: __name__ is greeterHello, Bob!The main block is skipped. greet() is available for reuse.
This allows Python scripts to have two purposes: they can be run directly to execute their main logic, or they can be imported into another module without executing that main logic.
The main() Pattern
Section titled “The main() Pattern”A common convention is to put the program’s logic in a main() function and call it from the guard.
def main(): name = input('Name: ') print(f'Hello, {name}!')
if __name__ == '__main__': main()This keeps the top level tidy and lets tests import and call main() or other functions in the file without side effects.
Import Style Guide
Section titled “Import Style Guide”PEP 8, Python’s style guide, recommends:
- Put imports at the top of the file, after any module docstring.
- Group them in this order, with a blank line between groups: standard library, third-party packages, then your own modules.
- Keep each group alphabetical.
- Use one
importper line (but several names in afromimport are fine). - Prefer absolute imports to relative ones outside of packages.
import jsonimport osfrom datetime import date
import requests
from myapp.utils import slugifyCommon Mistakes
Section titled “Common Mistakes”| Mistake | Problem | Fix |
|---|---|---|
import math then sqrt(36) | NameError: name 'sqrt' is not defined | math.sqrt(36) or from math import sqrt |
from math import sqrt then math.sqrt(36) | NameError: name 'math' is not defined | sqrt(36), or import math |
import math as m then math.pi | NameError, only the alias exists | m.pi |
math.sqroot(4) | AttributeError: module 'math' has no attribute 'sqroot' | Check the spelling with dir(math) |
import numpyy | ModuleNotFoundError: No module named 'numpyy' | Fix the name, or pip install the package |
from math import foo | ImportError: cannot import name 'foo' from 'math' | The module does not define that name |
from module import * | Namespace collisions, even replacing built-ins | Import explicit names |
A file named random.py or math.py | Hides the standard module | Use a different filename |
Installing with pip for the wrong Python | ModuleNotFoundError anyway | Use python -m pip install ... |
Expecting a second import to re-run a module | Modules load once | importlib.reload(module) |
| Two modules importing each other | Circular import errors | Move shared code into a third module |
Top-level code with no __main__ guard | It runs on import, causing side effects | Wrap it in if __name__ == '__main__': |
Best Practices Checklist
Section titled “Best Practices Checklist”- Use the standard library before writing your own solution or installing a package.
- Put all imports at the top of the file, grouped as standard library, third-party, then local.
- Prefer
import moduleor explicitfrom module import nameover wildcard imports. - Use aliases to shorten long names or resolve conflicts, and follow community conventions such as
npandpd. - Never name your own files after standard library modules.
- Use
help(),dir(), and the official documentation to explore a module. - Guard script entry points with
if __name__ == '__main__':so the file can be both run and imported. - Install third-party packages into a virtual environment with
python -m pip.