Python Cheat Sheet (3.8+)

Modern Python syntax — functions, comprehensions, async/await, dataclasses, FastAPI, Pydantic — with copy-paste examples

Basics & Data Types
Basic Variables, print, type
name = "Alice" # str
age = 30 # int
price = 19.99 # float
active = True # bool
nothing = None # NoneType
print(f"Hello {name}") # f-string (3.6+)
print("Score:", score) # multiple args
type(value) # returns type object
💡 Python is dynamically typed. Use type hints for clarity: def greet(name: str) -> None:
Basic Collections: list, dict, set, tuple
# List — mutable, ordered
nums = [1, 2, 3]
nums.append(4)
nums[0] = 99
# Tuple — immutable, ordered
point = (10, 20)
x, y = point # unpacking
# Dict — key-value map
user = {"id": 1, "name": "Alice"}
user["email"] = "a@example.com"
user.get("phone", "N/A") # safe get
# Set — unique, unordered
tags = {"python", "fastapi", "pydantic"}
tags.add("async")
💡 list and dict are mutable. tuple and frozenset are immutable. Use collections.defaultdict for auto-initializing dicts.

Truthiness & Boolean Context

Falsy values: False, None, 0, 0.0, "", [], {}, (), set()

if mylist: # checks len()>0
if mydict: # checks len()>0
if x is None: # explicit None check
if not items: # empty check
Control Flow
Control if / elif / else
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
else:
grade = "C"
# Ternary
status = "active" if user.active else "inactive"
💡 Indentation defines blocks. 4 spaces per PEP 8. No parentheses needed around conditions.

Loops

for with range
for i in range(5): # 0..4
for i in range(1, 6): # 1..5
for i in range(0, 10, 2): # step 2
for over iterable
for item in items:
print(item)


for i, item in enumerate(items):
print(i, item)
while
while running:
...
if stop: break
continue # skip to next
Functions
Func def — define function
def greet(name):
return f"Hello {name}"
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
# *args, **kwargs
def log(msg, *args, **kwargs):
print(msg, args, kwargs)
log("Error", 404, exc="timeout")
# → Error (404,) {'exc': 'timeout'}
💡 *args collects positional extras as tuple. **kwargs collects keyword extras as dict. Positional-only (before /) and keyword-only (after *) params available in 3.8+.
Func lambda — anonymous function
square = lambda x: x * x
result = square(5) # 25
# Used with map/filter/sorted
nums = [1, 2, 3]
doubled = list(map(lambda x: x*2, nums))
# key functions
pairs = [(1, 'one'), (3, 'three'), (2, 'two')]
pairs.sort(key=lambda p: p[1]) # sort by string
⚠️ Keep lambdas simple. For anything complex, use def. Python's lambda is limited to single expression (no statements).

Default Args & Closures

Default values
def greet(name="World"):
return f"Hello {name}"


Keyword args order
def f(pos, /, standard, *, kw_only): ...
# pos: positional-only, kw_only: keyword-only
Closure (captures outer var)
def make_multiplier(n):
def multiply(x):
return x * n
return multiply
double = make_multiplier(2)
Comprehensions
Comp List comprehension
squares = [x**2 for x in range(10)]
# with condition
even_squares = [x**2 for x in range(10) if x % 2 == 0]
# if-else inside
labels = ["even" if x%2==0 else "odd" for x in nums]
💡 List comprehensions are fast and idiomatic. Use when building a new list. Don't use for side effects — use for loop instead.

Dict & Set Comprehensions

Dict comprehension
square_map = {x: x**2 for x in range(5)}
# {0:0, 1:1, 2:4, 3:9, 4:16}
Set comprehension
unique_squares = {x**2 for x in [1, -2, 3, -2, 1]}
# {1, 4, 9}
Generator expression (lazy)
gen = (x**2 for x in range(1000000))
# values computed on demand
Context Managers & Decorators
Adv with — context manager (file I/O)
# File auto-close
with open("data.txt", "r") as f:
content = f.read() # file closes automatically
# Multiple context managers
with open("in.txt") as fin, open("out.txt", "w") as fout:
fout.write(fin.read())
💡 with guarantees cleanup even on exception. Custom context managers implement __enter__ / __exit__ or use @contextmanager decorator from contextlib.
Adv @dataclass — boilerplate-free classes
from dataclasses import dataclass

@dataclass
class Point:
x: float
y: float
# auto __init__, __repr__, __eq__
from dataclasses import dataclass, field

@dataclass
class User:
id: int
name: str
tags: list[str] = field(default_factory=list)
💡 @dataclass auto-generates __init__, __repr__, __eq__. field(default_factory=list) avoids mutable default pitfall. Python 3.10+ supports list[str] syntax for type hints.

Custom Decorator

import functools

def timer(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"{func.__name__} took {time.time()-start:.2f}s")
return result
return wrapper

@timer
def slow_func():
time.sleep(1)
💡 Always use @functools.wraps(func) to preserve __name__, __doc__ of decorated function. Decorators are just callables that wrap functions.
Async / Await (Python 3.8+)
Async async def / await — concurrency
import asyncio

async def fetch_data():
await asyncio.sleep(1) # non-blocking sleep
return {"result": 42}

async def main():
data = await fetch_data()
print(data)

asyncio.run(main())
💡 async def defines coroutine function. await pauses until coroutine completes. Run with asyncio.run() (main) or await inside another async function. Use FastAPI or Starlette for web apps.

Concurrent Execution

asyncio.gather — run concurrently
results = await asyncio.gather(fetch(1), fetch(2), fetch(3))
# all run concurrently, return list of results
asyncio.create_task — fire-and-forget
task = asyncio.create_task(background_job())
# don't await immediately
💡 gather() waits for all. create_task() schedules and returns Task immediately. Cancel tasks on shutdown if needed.
Error Handling
Ctrl try / except / finally
try:
result = 10 / divisor
except ZeroDivisionError:
print("Cannot divide by zero")
except Exception as e:
print(f"Unexpected: {e}")
else:
print("Success!", result)
finally:
cleanup() # always runs
💡 else runs if no exception. finally runs always (cleanup). Catch specific exceptions first, broad ones last.

Raise Exceptions

Raise built-in
raise ValueError("Invalid input")
raise TypeError("Expected str")
Custom exception
class AppError(Exception):
pass

raise AppError("Something went wrong")
Modern Python (3.8+)
Modern := walrus — assignment expression
# Assign inside expression
if (n := len(items)) > 0:
print(f"List has {n} items")
# While reading lines from file
while (line := f.readline()):
process(line)
💡 := assigns and returns value. Reduces duplicate calls. Use sparingly — readability matters. Not for complex expressions.
Modern match — pattern matching (3.10+)
match command:
case ["goto", x, y]:
print(f"Go to {x},{y}")
case ["quit"]:
print("Goodbye")
case _:
print("Unknown")
match status:
case 200:
print("OK")
case 404:
print("Not found")
case int(code) if code >= 500:
print("Server error")
💡 Python's match is like switch but powerful — matches on structure, type, and value. Guard clauses (if after case) add conditions.
Modern Positional-only & keyword-only args (3.8+)
def greet(name, /, greeting="Hello", *, excited=False):
msg = f"{greeting} {name}"
if excited: msg += "!"
return msg

greet("Bob") # OK
greet(name="Bob") # ❌ name is positional-only
greet("Bob", "Hi", excited=True) # OK
💡 / marks preceding args positional-only. * marks following args keyword-only. Signals API intent and prevents accidental misuse.

About This Tool

The Python Cheat Sheet covers essential Python 3.8+ syntax and idioms. From basics like variables and collections, through functions, comprehensions, and async/await, to modern features like dataclasses and structural pattern matching. Each snippet is copy-ready and includes brief explanations.

Python Philosophy

"There should be one — and preferably only one — obvious way to do it." — The Zen of Python

This cheat sheet favors idiomatic Python: list comprehensions over map/filter, f-strings over format(), with for resource cleanup, and explicit is better than implicit.

Frequently Asked Questions

When should I use a list comprehension vs a for loop?

Use list comprehensions when you're building a new list from an iterable with transformation and optional filtering. Use a for loop when you need side effects (printing, mutating external vars, complex multi-step logic that doesn't fit in one expression). List comps are faster and more readable for simple transformations.

What's the difference between async and threading?

async/await is cooperative concurrency — tasks explicitly yield control at await points. It's single-threaded and ideal for I/O-bound work (API calls, file/DB ops). Threading is preemptive OS-managed concurrency — threads run truly parallel but share memory, requiring locks for thread-safety. Use async for many simultaneous I/O operations; use threading (or multiprocessing) for CPU-bound work.

Should I use Pydantic or dataclasses?

Use @dataclass for simple, internal data containers with no validation — it's built-in and zero-dependency. Use Pydantic when you need runtime validation, parsing, JSON (de)serialization, ORM-like features, or complex type coercion. Pydantic v2 is much faster and has better error messages. For public APIs and config, Pydantic. For private simple structs, dataclasses.

Is this tool free?

Yes, completely free with no sign-up required.

Related Tools