Python Cheatsheet

Functions

Use this Python reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Defining Functions

def greet(name):
    """Return a greeting string."""
    return f"Hello, {name}!"

# No return value returns None implicitly
def side_effect(x):
    print(x)

# Call
result = greet("Alice")

Parameters and Arguments

# Positional
def add(a, b):
    return a + b

add(1, 2)          # positional
add(b=2, a=1)      # keyword (any order)

# Default values — mutable defaults are a common bug!
def append_to(item, lst=None):   # correct
    if lst is None:
        lst = []
    lst.append(item)
    return lst

# BAD: def append_to(item, lst=[]):  # lst shared across calls

# Positional-only (Python 3.8+, before /)
def pos_only(a, b, /, c):
    pass
# pos_only(1, 2, 3)  — a and b must be positional

# Keyword-only (after *)
def kw_only(a, *, b, c=10):
    pass
# kw_only(1, b=2)    — b must be keyword

# Both
def mixed(pos_only, /, normal, *, kw_only):
    pass

args and *kwargs

# *args — variable positional arguments (tuple)
def total(*nums):
    return sum(nums)

total(1, 2, 3, 4)   # 10

# **kwargs — variable keyword arguments (dict)
def info(**kw):
    for k, v in kw.items():
        print(f"{k}: {v}")

info(name="Alice", age=30)

# Combined signature (order matters)
def func(a, b, *args, key=None, **kwargs):
    pass

# Unpacking when calling
lst = [1, 2, 3]
dct = {"key": "val"}
func(*lst)        # unpack list as positional args
func(**dct)       # unpack dict as keyword args
func(*lst, **dct)

Return Values

def nothing():
    return           # returns None
    # or just fall off the end

def single():
    return 42

def multiple():
    return 1, 2, 3   # returns tuple (1, 2, 3)

a, b, c = multiple()  # unpacking

Lambda Functions

Anonymous single-expression functions.

square = lambda x: x ** 2
square(5)   # 25

add = lambda a, b: a + b
add(3, 4)   # 7

# Common use: key for sort/min/max
pairs = [(1, "b"), (2, "a")]
pairs.sort(key=lambda p: p[1])          # sort by second element
min(words, key=lambda w: len(w))        # shortest word
sorted(data, key=lambda x: -x)         # descending

# Lambda with default
fn = lambda x, n=2: x ** n

Closures

def make_counter(start=0):
    count = start
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

c = make_counter()
c()   # 1
c()   # 2

# Closure captures variable by reference (gotcha in loops!)
fns = []
for i in range(3):
    fns.append(lambda x, i=i: x + i)  # default arg captures current i

Decorators

import functools

def my_decorator(func):
    @functools.wraps(func)   # preserve __name__, __doc__
    def wrapper(*args, **kwargs):
        print("before")
        result = func(*args, **kwargs)
        print("after")
        return result
    return wrapper

@my_decorator
def greet(name):
    print(f"Hi {name}")

# Equivalent to: greet = my_decorator(greet)

See the Decorators cheatsheet for full coverage.

Type Hints

def add(a: int, b: int) -> int:
    return a + b

def greet(name: str = "World") -> str:
    return f"Hello, {name}!"

# Complex types (Python 3.9+ built-ins; or import from typing)
def process(items: list[int]) -> dict[str, int]:
    return {"sum": sum(items)}

from typing import Optional, Union, Callable, Any, TypeVar

def find(lst: list[int], val: int) -> Optional[int]:
    ...

def either(x: Union[int, str]) -> str:
    return str(x)

# Python 3.10+ union shorthand
def fn(x: int | str | None) -> None:
    pass

T = TypeVar("T")
def identity(x: T) -> T:
    return x

Generators

def count_up(n):
    for i in range(n):
        yield i

gen = count_up(5)
next(gen)   # 0
next(gen)   # 1
list(gen)   # [2, 3, 4]

# yield from — delegate to sub-generator
def flatten(lst):
    for item in lst:
        if isinstance(item, list):
            yield from flatten(item)
        else:
            yield item

# Generator expression (no function needed)
gen = (x ** 2 for x in range(10))
sum(x ** 2 for x in range(10))  # 285

# send() — two-way communication
def accumulator():
    total = 0
    while True:
        value = yield total
        if value is None:
            break
        total += value

acc = accumulator()
next(acc)        # prime the generator
acc.send(10)     # 10
acc.send(20)     # 30

Higher-Order Functions

# map — apply function to each element
list(map(str, [1, 2, 3]))          # ['1', '2', '3']
list(map(lambda x: x*2, range(5))) # [0, 2, 4, 6, 8]

# filter — keep elements where function returns True
list(filter(None, [0, 1, "", "a"])) # [1, 'a']  (None = identity)
list(filter(lambda x: x > 0, [-1, 0, 1, 2]))  # [1, 2]

# reduce
from functools import reduce
reduce(lambda acc, x: acc + x, [1, 2, 3, 4])  # 10

# sorted with key
sorted(["banana", "apple", "cherry"], key=len)  # by length
sorted(data, key=lambda x: (x.priority, x.name))  # multi-key

# Partial application
from functools import partial
double = partial(pow, exp=2)  # won't work due to keyword; typical use:
add5 = partial(lambda a, b: a + b, 5)
add5(3)  # 8

functools Essentials

from functools import wraps, lru_cache, cache, reduce, partial, total_ordering

# Memoization
@lru_cache(maxsize=128)
def fib(n):
    if n < 2: return n
    return fib(n-1) + fib(n-2)

fib.cache_info()   # CacheInfo(hits=..., misses=..., ...)
fib.cache_clear()

@cache              # unbounded cache (Python 3.9+)
def expensive(n):
    ...

# total_ordering — define __eq__ + one of lt/le/gt/ge, get the rest
@total_ordering
class Weight:
    def __init__(self, kg): self.kg = kg
    def __eq__(self, other): return self.kg == other.kg
    def __lt__(self, other): return self.kg < other.kg

Recursion

import sys
sys.getrecursionlimit()      # default 1000
sys.setrecursionlimit(5000)  # increase if needed

def factorial(n):
    if n <= 1:
        return 1
    return n * factorial(n - 1)

# Tail-call style (Python doesn't optimize tail calls, but readable)
def factorial(n, acc=1):
    if n <= 1:
        return acc
    return factorial(n - 1, acc * n)

Introspection

import inspect

inspect.signature(func)          # Signature object
inspect.getfullargspec(func)     # args, varargs, varkw, defaults
inspect.getsource(func)          # source code as string
inspect.isfunction(obj)          # True for def-defined functions
inspect.ismethod(obj)            # True for bound methods
inspect.isbuiltin(obj)           # True for built-in functions

func.__name__        # "func"
func.__doc__         # docstring
func.__annotations__ # type hints dict
func.__defaults__    # tuple of default values
func.__code__.co_varnames  # local variable names