In the previous lesson you learned to import modules and created your own. Now it's time to open the gift that comes with every Python installation: the standard library, more than two hundred ready-made, tested, documented modules covering math, randomness, dates, text, files and much more — nothing to install, no pip, no .venv to touch. Pythonistas call it the "batteries included" philosophy: before programming something, ask whether the standard library already ships it. This lesson is a guided tour, not an encyclopedia: you'll see the modules you'll use most, with short examples applied to Papyrus, and a map of which ones we'll revisit in depth during the rest of the course. We'll close the module with the definitive (for now) version of menu.py, rewritten on top of papyrus_utils.
Contents
- The "batteries included" philosophy
math: mathematics beyond the operatorsrandom: randomness for raffles and test datadatetime: dates and times for the ordersstringandtextwrap: text utilitiesstatistics: basic statistics without installing anythingsysandos: talking to the system- Map of the standard library in this course
- Closing the module:
menu.pyreorganized
The "batteries included" philosophy
Everything you saw in 03-04 applies as is: import math works exactly like import papyrus_utils, except the file lives in the standard library folders of sys.path instead of in your project. The official documentation (docs.python.org, Library Reference section) is the canonical reference; help(module) in the REPL is the quick shortcut. The skill to train isn't memorizing functions, but knowing that the module exists: whoever knows statistics exists doesn't reimplement the mean with a loop.
math: mathematics beyond the operators
The operators (+, **, //...) cover the basics; math supplies the rest:
import math
print(math.sqrt(16)) # 4.0 square root
print(math.ceil(2.04)) # 3 ALWAYS rounds up
print(math.floor(9.83)) # 9 ALWAYS rounds down
print(math.pi) # 3.141592653589793A shop example: books arrive in boxes of 6 units. If Ana needs 20 copies, how many boxes does she order?
boxes = math.ceil(20 / 6)
print(f"Order: {boxes} boxes") # 4 (3.33 boxes isn't enough: you round up)Watch the difference from round(), which you already know: round(3.33) gives 3 (to the nearest), math.ceil(3.33) gives 4 (ceiling). For "how many containers do I need?", always ceil.
random: randomness for raffles and test data
import random
print(random.randint(1, 6)) # integer between 1 and 6, BOTH included
print(random.choice(catalog)) # one random element from the list
print(random.sample(catalog, 2)) # 2 distinct elements, no repeats
print(round(random.uniform(5, 25), 2)) # random float between 5 and 25At Papyrus, random.choice() powers the "surprise recommendation of the day", and random.sample() a raffle among members without repeating a winner. Its other big professional use: generating test data (prices, stock levels) to rehearse programs before you have real data. And a lab trick: random.seed(42) pins the generator's seed so the "random" sequence is reproducible — essential for debugging and, later on, for the tests in module 9.
datetime: dates and times for the orders
The datetime module contains (among others) the classes date and datetime — yes, module and class share a name, the source of endless confusion. The usual thing is to import the classes directly:
from datetime import date, datetime, timedelta
today = date.today()
now = datetime.now()
print(today) # 2026-07-13
print(f"{now:%d/%m/%Y %H:%M}") # 13/07/2026 10:45 (custom format)
# The "Faust" order arrives in 7 days:
arrival = today + timedelta(days=7)
print(f"The Faust order will arrive on {arrival:%d/%m/%Y}")
# How many days has Luis been waiting? (subtracting dates gives a timedelta)
ordered = date(2026, 7, 1)
print(f"Days waiting: {(today - ordered).days}") # 12Three key ideas: date objects can be operated on (adding a timedelta, subtracting two dates), they're formatted in f-strings with the codes %d, %m, %Y, %H, %M, and they're constructed with date(year, month, day). With this, Papyrus can date receipts and calculate deliveries; when the shop stores orders in files (module 6), dates will travel as text and datetime will parse them back.
string and textwrap: text utilities
Two small but handy modules. string offers ready-made constants for validation:
import string
print(string.ascii_lowercase) # abcdefghijklmnopqrstuvwxyz
print(string.digits) # 0123456789
print(string.punctuation) # !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~For example, to check that a discount code uses only uppercase letters and digits: all(c in string.ascii_uppercase + string.digits for c in code).
textwrap fits paragraphs to a given width — perfect so a book's synopsis fits on Papyrus's 40-column receipt:
import textwrap
synopsis = ("Faust, a dissatisfied scholar, strikes a deal with "
"Mephistopheles: youth and knowledge in exchange for his soul.")
print(textwrap.fill(synopsis, width=40))Faust, a dissatisfied scholar, strikes a deal with Mephistopheles: youth and knowledge in exchange for his soul.
statistics: basic statistics without installing anything
Before reaching pandas (module 11), everyday statistics already come included:
import statistics
prices = [12.50, 9.95, 15.90, 21.00]
print(statistics.mean(prices)) # 14.8375 mean
print(statistics.median(prices)) # 14.2 medianWith mean() Ana answers "what's the average price of my catalog?" in one line. The median holds up better against extreme values: if a 300 EUR facsimile came in, the mean would shoot up while the median would barely move.
sys and os: talking to the system
From sys you already know sys.path (lesson 03-04). Its other star is sys.argv: the list of command-line arguments the script was run with — the script-level equivalent of a function's parameters. sys.argv[0] is the name of the script itself, and the rest is whatever was typed after it:
# lookup.py — usage: python lookup.py <title>
import sys
from papyrus_utils import find_book
catalog = ["The Odyssey", "Hamlet", "Don Quixote"]
if len(sys.argv) < 2:
print("Usage: python lookup.py <title>")
else:
index = find_book(catalog, sys.argv[1])
print("In catalog" if index is not None else "Not available")This way Ana checks without going through the menu: "one-shot" scripts for quick tasks. Careful: the arguments always arrive as strings, just like with input().
For its part, os (and its modern companion pathlib) communicates with the operating system: os.getcwd() tells you which folder you're in, os.listdir() lists files, and onward from there — creating folders, checking whether a file exists, deleting. This is just an introduction: it stars in module 6, when the catalog lives in files.
Map of the standard library in this course
| Module | What it's for | Where it's used in this course |
|---|---|---|
math |
Roots, ceilings/floors, constants | From now on, wherever needed |
random |
Randomness, sampling, test data | Here; sample data in modules 4-6 |
datetime |
Dates, times, time arithmetic | Here; order dates in module 6 (CSV/JSON) |
string / textwrap |
Text constants / tailored paragraphs | Useful curiosities; strings in depth in 04-05 |
statistics |
Mean, median and company | Here; a prelude to pandas (module 11) |
sys |
argv, path, interpreter exit |
Here and in debugging (module 9) |
os / pathlib |
Files, folders, paths | Module 6 |
collections |
Extra data structures | Module 4 (04-06) |
csv / json |
Reading and writing structured data | Module 6 |
logging |
Professional event logging | Module 7 |
unittest / pdb |
Testing and debugging | Module 9 |
asyncio / threading |
Concurrency | Module 8 |
Keep this table as a compass: much of the syllabus ahead of you is, at heart, learning to use the standard library well.
Closing the module: menu.py reorganized
The promise from module 2 is settled. The final version of menu.py imports papyrus_utils (lesson 03-04), splits the work into functions with one responsibility each (03-01), uses keyword arguments (03-02) and even dates the session with datetime:
"""Management menu for the Papyrus bookshop."""
from datetime import date
from papyrus_utils import STORE_NAME, find_book, final_price
catalog = ["The Odyssey", "Hamlet", "Don Quixote"]
prices = [12.50, 9.95, 15.90]
stocks = [4, 6, 8]
def show_catalog():
"""Print the table of titles, prices and stock."""
print(f"\n{'Title':<12} {'Price':>8} {'Stock':>6}")
print("-" * 28)
for title, price, stock in zip(catalog, prices, stocks):
print(f"{title:<12} {price:>6.2f} EUR {stock:>6}")
def look_up_book():
"""Ask for a title and show its card, member price included."""
wanted = input("Title to search for: ")
if not wanted:
print("You didn't type anything.")
return
index = find_book(catalog, wanted)
if index is None:
print(f"'{wanted}' is not in the catalog.")
return
base = prices[index]
print(f"'{catalog[index]}': {base:.2f} EUR "
f"(members: {final_price(base, member=True):.2f} EUR), stock {stocks[index]}.")
def run_menu():
"""Main loop of the shop menu."""
print(f"{STORE_NAME} management — {date.today():%d/%m/%Y}")
while True:
print("\n1. View catalog\n2. Look up a book\n3. Exit")
match input("Choose an option (1-3): "):
case "1":
show_catalog()
case "2":
look_up_book()
case "3":
print(f"Closing {STORE_NAME}. See you tomorrow, Ana!")
break
case _:
print("Invalid option. Choose 1, 2 or 3.")
if __name__ == "__main__":
run_menu()Compare it with the monolithic version from module 2: it does the same and a bit more (the date, the member price on the card), but now every piece has a name, a docstring and a place. look_up_book() uses return as a guard — its early exits replace the continue of the old version. The business logic lives in papyrus_utils (reusable from receipt.py or member_sale.py), the presentation lives here, and the __main__ block lets another script do from menu import show_catalog without launching the whole menu. This is no longer a script: it's a small, well-organized program.
Common Mistakes and Tips
- Reinventing the wheel: writing your own mean, your own shuffle or your own line wrapping. Before programming a "generic" utility, search the documentation: it probably already exists, bug-free and faster.
import datetimeand then usingdatetime.now():NameError/AttributeErrorfrom confusing module and class. Eitherimport datetime+datetime.datetime.now(), orfrom datetime import datetime+datetime.now(). Pick one style and be consistent.- Expecting
sys.argvto bring numbers: everything arrives as strings; convert withint()/float()just like withinput(). - Forgetting that
sys.argv[0]is the script: the first real argument issys.argv[1], and you must checklen(sys.argv)before using it. - Naming files after standard modules: a
random.pyorstring.pyof yours shadows the official one (lesson 03-04). The symptoms are absurd errors in modules that have "always worked". - Using
randomfor anything security-related: for raffles and tests it's perfect; for passwords or tokens there's thesecretsmodule. - Tip: spend five minutes skimming the index of the official Library Reference. Not to learn it, but so that "I think there's a module for this" becomes your first reflex.
Exercises
Exercise 1: the book club raffle
Write raffle.py: given members = ["Luis", "Marta", "Chen", "Aitana", "Pau"], use random.sample() to pick two distinct winners of a copy of "Faust" and print each one with the pick-up deadline: today plus 15 days, formatted dd/mm/yyyy (use date.today() and timedelta).
Exercise 2: express catalog report
Write report.py which, with prices = [12.50, 9.95, 15.90, 21.00], prints: the average price and the median (statistics module, both with :.2f), the highest and lowest price (built-in functions max()/min()), and how many boxes of 6 units Ana needs to store 31 books (math module). Finish with a separator line of dashes generated with "-" * 30.
Exercise 3: lookup with arguments and papyrus_utils
Extend this lesson's lookup.py: it must accept python lookup.py <title> [member]. If the title exists in the catalog, print its final price — the member price if the second argument is exactly member, the regular one otherwise — using final_price() from papyrus_utils. If it doesn't exist or the title is missing, print the appropriate notice. Try it with python lookup.py Hamlet member (it must give 9.83 EUR).
Solutions
Exercise 1:
import random
from datetime import date, timedelta
members = ["Luis", "Marta", "Chen", "Aitana", "Pau"]
winners = random.sample(members, 2)
deadline = date.today() + timedelta(days=15)
for name in winners:
print(f"{name}: pick up your 'Faust' by {deadline:%d/%m/%Y}")sample() guarantees two distinct names (with choice() twice, Luis could win both copies). The date is calculated once and reused.
Exercise 2:
import math
import statistics
prices = [12.50, 9.95, 15.90, 21.00]
print(f"Average price: {statistics.mean(prices):.2f} EUR") # 14.84 EUR
print(f"Median: {statistics.median(prices):.2f} EUR") # 14.20 EUR
print(f"Most expensive: {max(prices):.2f} EUR") # 21.00 EUR
print(f"Cheapest: {min(prices):.2f} EUR") # 9.95 EUR
print("-" * 30)
print(f"Boxes for 31 books: {math.ceil(31 / 6)}") # 6Notice the natural mix of built-in functions (max, min) and modules (statistics, math): the standard library begins where the built-ins end.
Exercise 3:
import sys
from papyrus_utils import find_book, final_price
catalog = ["The Odyssey", "Hamlet", "Don Quixote"]
prices = [12.50, 9.95, 15.90]
if len(sys.argv) < 2:
print("Usage: python lookup.py <title> [member]")
else:
index = find_book(catalog, sys.argv[1])
if index is None:
print(f"'{sys.argv[1]}' is not in the catalog.")
else:
is_member = len(sys.argv) > 2 and sys.argv[2] == "member"
print(f"{catalog[index]}: {final_price(prices[index], member=is_member):.2f} EUR")is_member takes advantage of the and short-circuit: if there's no third argument, it never tries to read sys.argv[2] (avoiding an IndexError). Note the imports in two PEP 8 blocks: standard (sys) on top, your own (papyrus_utils) below.
Conclusion
Module 3 closes the circle it opened: the Papyrus code no longer lives scattered around. You know how to define functions with def, docstring and return (03-01); how to design their signatures with positional and keyword arguments, default values, *args/**kwargs, and walk parallel lists with zip() (03-02); how to write throwaway lambdas as the criterion for sorted(), min() and max() (03-03); how to split code into modules of your own like papyrus_utils.py with if __name__ == "__main__" and packages with __init__.py (03-04); and how to find your way around the standard library with math, random, datetime, statistics and sys.argv (03-05). The new menu.py — small functions, imported business logic, separate presentation — is the proof of maturity. But a crack remains in plain sight: the catalog is three parallel lists that must be kept in sync by hand, and it's already forced us into juggling with zip() and indexes. Module 4 strikes exactly there: Python's data structures — lists in depth, tuples, dictionaries, sets and the gems of collections — with which every Papyrus book will at last be a single piece of information, not a row number spread across three lists.
Python Programming Course
Module 1: Introduction to Python
- Introduction to Python
- Setting Up the Development Environment
- Python Syntax and Basic Data Types
- Variables and Constants
- Basic Input and Output
- Virtual Environments and Package Management
Module 2: Control Structures
Module 3: Functions and Modules
- Defining Functions
- Function Arguments
- Lambda Functions
- Modules and Packages
- Standard Library Overview
Module 4: Data Structures
Module 5: Object-Oriented Programming
Module 6: File Handling
Module 7: Error and Exception Handling
- Introduction to Exceptions
- Handling Exceptions
- Raising Exceptions
- Custom Exceptions
- Best Practices and Error Logging
Module 8: Advanced Topics
- Type Hints
- Decorators
- Generators
- Context Managers
- Concurrency: Threads and Processes
- Asyncio for Asynchronous Programming
Module 9: Testing and Debugging
- Introduction to Testing
- Unit Testing with unittest
- Testing with pytest
- Test-Driven Development
- Debugging Techniques
- Using pdb for Debugging
Module 10: Web Development with Python
- Introduction to Web Development
- Flask Framework Fundamentals
- Building REST APIs with Flask
- Introduction to Django
- Building Web Applications with Django
Module 11: Data Science with Python
- Introduction to Data Science
- NumPy for Numerical Computing
- Pandas for Data Manipulation
- Matplotlib for Data Visualization
- Introduction to Machine Learning with scikit-learn
