Skip to content

Common Python Libraries

Numerous libraries extend Python’s capabilities, making it a versatile language for various applications. Here are some of the most common Python libraries you should know about:

These libraries appear in real projects, interviews, and daily development work.

LibraryMain Use
osOS operations, file system tasks, environment variables
sysPython runtime info, command-line arguments, exits
typingType hints for better code clarity, IDE support, and error catching
jsonConvert Python data to/from JSON
csvRead and write CSV files
sqlite3Lightweight embedded SQL database
requestsHTTP client for APIs and web calls
datetimeDates, times, formatting, arithmetic
pathlibModern and clean path/file handling
python-dotenvLoad environment variables from .env
loggingStructured application logs
flaskBuild simple web applications and APIs
tkinterBuild desktop GUI applications
graph TD Core["Python App"] --> FS["os + pathlib"] Core --> Runtime["sys"] Core --> Types["typing"] Core --> Data["json + csv"] Core --> DB["sqlite3"] Core --> HTTP["requests"] Core --> Time["datetime"] Core --> Config["python-dotenv"] Core --> Logs["logging"] Core --> Web["flask"] Core --> GUI["tkinter"]

Use os when you need low-level operating system interaction.

  • Working directories and files
  • Environment variables
  • Process-related values
  • os.getcwd() -> current working directory
  • os.listdir(path) -> list directory contents
  • os.makedirs(path, exist_ok=True) -> create folders safely
  • os.remove(path) -> delete file
  • os.environ.get("KEY") -> read environment variable
import os
print("Current directory:", os.getcwd())
os.makedirs("data/output", exist_ok=True)
api_key = os.environ.get("API_KEY")
print("API key loaded:", bool(api_key))
  • Prefer pathlib for path operations in new code
  • Use os.environ.get() instead of direct indexing to avoid KeyError

Use sys for runtime info and command-line scripts.

  • Read script arguments
  • Exit program with status code
  • Inspect Python path/version
  • sys.argv -> command-line arguments
  • sys.exit(code) -> terminate program
  • sys.version -> Python version string
  • sys.path -> import search paths
import sys
if len(sys.argv) < 2:
print("Usage: python app.py <name>")
sys.exit(1)
name = sys.argv[1]
print(f"Hello, {name}")
  • Validate argument count and format before use
  • Return non-zero exit codes for failures in automation scripts

Use typing to add type information to your code. Type hints clarify the expected data types for function arguments and return values.

  1. Catches errors early → IDEs and type checkers find bugs before runtime
  2. Self-documenting code → Other developers understand what types are expected without reading docs
  3. Better IDE support → Autocomplete and type checking work better
  4. Enables static analysis → Tools like mypy validate code without running it
  5. Improves maintainability → Code is easier to refactor when types are explicit
  • int, str, float, bool -> basic types
  • List[int] -> list of integers
  • Dict[str, int] -> dictionary with string keys and integer values
  • Tuple[str, int] -> tuple with specific types
  • Optional[str] -> string or None
  • Union[str, int] -> can be string or integer
  • Callable[[int, str], bool] -> function taking int + str, returning bool
  • Any -> any type (use sparingly)
from typing import List, Dict, Optional
def greet(name: str, age: int) -> str:
"""Greet a person with their age."""
return f"Hello {name}, you are {age} years old"
def find_user(user_id: int) -> Optional[Dict[str, str]]:
"""Return user data or None if not found."""
users = {1: {"name": "Alice"}, 2: {"name": "Bob"}}
return users.get(user_id)
def process_scores(scores: List[int]) -> float:
"""Calculate average score."""
return sum(scores) / len(scores) if scores else 0.0
# Function calls
print(greet("Sahil", 25))
print(find_user(1))
print(process_scores([85, 90, 78]))
from typing import List, Dict, Tuple, Union, Callable
# A list of dictionaries (common with API responses)
users: List[Dict[str, Union[str, int]]] = [
{"name": "Alice", "age": 25},
{"name": "Bob", "age": 30},
]
# Tuple with fixed types
coordinates: Tuple[float, float] = (10.5, 20.3)
# Callback function type
process_callback: Callable[[str], int] = lambda x: len(x)
# Optional values (might be None)
api_key: Optional[str] = None
from typing import List, Optional
class User:
def __init__(self, name: str, email: str) -> None:
self.name: str = name
self.email: str = email
self.posts: List[str] = []
def add_post(self, title: str) -> None:
"""Add a post to user's list."""
self.posts.append(title)
def get_email(self) -> str:
return self.email
user = User("Sahil", "sahil@example.com")
user.add_post("My First Post")

Install mypy to check types without running code:

Terminal window
uv add --dev mypy
uv run mypy your_file.py

mypy catches type errors:

# This will be flagged by mypy
name: str = "Alice"
age: int = name # Error: incompatible types (str vs int)
  • Add type hints to function parameters and return values
  • Use Optional[T] for values that might be None, not Optional[Union[T, None]]
  • Use List, Dict, Tuple from typing for Python < 3.9, or use built-in list, dict for Python 3.9+
  • Keep types simple and readable; avoid overly complex unions
  • Type hints are optional but highly recommended for production code

json converts between Python objects and JSON text.

  • json.dumps(obj) -> Python object to JSON string
  • json.loads(text) -> JSON string to Python object
  • json.dump(obj, file) -> write JSON to file
  • json.load(file) -> read JSON from file
import json
user = {"name": "Sahil", "active": True, "score": 91}
# To string
payload = json.dumps(user, indent=2)
print(payload)
# To file
with open("user.json", "w", encoding="utf-8") as f:
json.dump(user, f, indent=2)
  • Use indent=2 for readable files
  • Use ensure_ascii=False when storing Unicode text
  • JSON supports basic types only (dict, list, str, int, float, bool, null)

csv is useful for tabular data exchange.

  • csv.reader() / csv.writer() for row-based access
  • csv.DictReader() / csv.DictWriter() for column-name access
import csv
rows = [
{"name": "A", "marks": 85},
{"name": "B", "marks": 92},
]
with open("marks.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=["name", "marks"])
writer.writeheader()
writer.writerows(rows)
with open("marks.csv", "r", newline="", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
print(row["name"], row["marks"])
  • Always use newline="" on Windows to avoid blank lines
  • Prefer DictReader and DictWriter for clearer code

sqlite3 provides a local SQL database stored in a single file.

  • Small to medium local apps
  • Prototypes and learning SQL
  • Desktop or offline tools
  1. Connect
  2. Create cursor
  3. Execute SQL
  4. Commit (for writes)
  5. Close connection
import sqlite3
conn = sqlite3.connect("app.db")
cur = conn.cursor()
cur.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)")
cur.execute("INSERT INTO users (name) VALUES (?)", ("Sahil",))
conn.commit()
cur.execute("SELECT id, name FROM users")
print(cur.fetchall())
conn.close()
  • Use parameterized queries (?) to prevent SQL injection
  • Wrap DB operations with try/except in production code

requests is the most popular Python library for making HTTP calls.

Terminal window
uv add requests
  • requests.get(url)
  • requests.post(url, json=data)
  • response.status_code
  • response.json()
  • response.raise_for_status()
import requests
url = "https://jsonplaceholder.typicode.com/todos/1"
response = requests.get(url, timeout=10)
response.raise_for_status()
data = response.json()
print(data["title"])
  • Always set timeout
  • Use raise_for_status() to catch HTTP errors early
  • Use Session() for repeated calls to the same host

Use datetime for timestamps, formatting, and date arithmetic.

  • Current date/time: datetime.now()
  • Parse string: datetime.strptime()
  • Format output: datetime.strftime()
  • Add/subtract using timedelta
from datetime import datetime, timedelta
now = datetime.now()
print("Now:", now.strftime("%Y-%m-%d %H:%M:%S"))
deadline = now + timedelta(days=7)
print("Deadline:", deadline.strftime("%Y-%m-%d"))
  • Store times in UTC for backend systems
  • Convert to local timezone only for display

pathlib gives object-oriented path operations and cleaner code than manual string paths.

  • Build paths with /
  • Check file existence
  • Read and write text quickly
  • Iterate directory contents
from pathlib import Path
base = Path("data")
base.mkdir(exist_ok=True)
file_path = base / "notes.txt"
file_path.write_text("Hello from pathlib\n", encoding="utf-8")
print(file_path.read_text(encoding="utf-8"))
  • Prefer Path over manual string concatenation
  • Keep file encoding explicit (utf-8)

python-dotenv - Environment Variables from .env

Section titled “python-dotenv - Environment Variables from .env”

python-dotenv loads variables from a .env file into environment variables.

Terminal window
uv add python-dotenv

.env

API_KEY=your_secret_key
DEBUG=true

app.py

from dotenv import load_dotenv
import os
load_dotenv()
api_key = os.getenv("API_KEY")
debug = os.getenv("DEBUG", "false").lower() == "true"
print("Key exists:", bool(api_key))
print("Debug:", debug)
  • Do not commit .env to version control
  • Keep secrets in environment variables, not hardcoded in source code

Use logging instead of print() for production-grade applications.

  • DEBUG -> detailed troubleshooting info
  • INFO -> normal events
  • WARNING -> unexpected but manageable event
  • ERROR -> operation failed
  • CRITICAL -> severe failure
import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s | %(levelname)s | %(message)s"
)
logging.info("Application started")
logging.warning("Cache miss for user profile")
logging.error("Database connection failed")
  • Include timestamps and level in format
  • Use logger.exception("...") inside except blocks for traceback
  • Write logs to file in long-running apps

flask is a lightweight framework for building web apps and APIs. It is beginner-friendly and great for learning backend development.

Terminal window
uv add flask
  • Flask(__name__) creates the app
  • @app.route("/") maps URLs to functions
  • request reads input from browser/client
  • jsonify() returns JSON responses
from flask import Flask, jsonify
app = Flask(__name__)
@app.route("/")
def home():
return "Hello, Flask!"
@app.route("/api/health")
def health():
return jsonify({"status": "ok"})
if __name__ == "__main__":
app.run(debug=True)
Terminal window
python app.py

Then open http://127.0.0.1:5000 in your browser.

graph TD Browser --> Route["Flask Route"] Route --> Function["Python Function"] Function --> Response["HTML or JSON Response"] Response --> Browser
  • Keep routes small and move business logic to separate functions/modules
  • Use debug=True only in development
  • Validate user input before processing

tkinter is Python’s built-in GUI library for desktop apps. You can create windows, buttons, labels, and input forms without extra installation.

  • Tk() creates the main window
  • Widgets: Label, Entry, Button
  • command= runs a function on button click
  • mainloop() keeps the UI running
import tkinter as tk
def greet():
name = name_entry.get().strip() or "Friend"
output_label.config(text=f"Hello, {name}!")
app = tk.Tk()
app.title("Greeting App")
app.geometry("320x180")
tk.Label(app, text="Enter your name:").pack(pady=8)
name_entry = tk.Entry(app, width=28)
name_entry.pack(pady=4)
tk.Button(app, text="Greet", command=greet).pack(pady=10)
output_label = tk.Label(app, text="")
output_label.pack(pady=6)
app.mainloop()
graph TD Start --> Window["Create Window"] Window --> Widgets["Add Widgets"] Widgets --> Loop["mainloop()"] Loop --> Click["User Clicks Button"] Click --> Handler["Run command function"] Handler --> Update["Update Label/State"] Update --> Loop
  • Keep callback functions short and clear
  • Validate input from Entry fields
  • For larger apps, split UI into classes/files