Python Study Notes — Misc
Personal notes from working through a few backend projects. Mostly things I keep forgetting
and have to look up.
List comprehensions vs generators
Comprehensions build the whole list in memory. Generators yield one at a time. For anything
iterating a file or a query result, generator. For anything you need to index into or pass around,
list. The square-bracket vs round-bracket difference is easy to miss in a code review.
Decorators and [Link]
Always use @[Link] in custom decorators or you lose the wrapped function's
__name__ and docstring, which breaks logging and Sphinx. Took me an hour to figure out
why my logs were full of 'wrapper' instead of the actual function name.
Context managers
[Link] turns a generator into a context manager. Useful for one-off
setup/teardown without writing a full class. Yield once, put cleanup in a finally block. Don't
yield twice or you get a RuntimeError.
Type hints I keep forgetting
Optional[X] is just shorthand for Union[X, None]. In 3.10+ you can write X | None instead,
which reads better. List[int] is now list[int] without the import. Callable signatures: Callable[[int,
str], bool] means takes int and str, returns bool.
Async pitfalls
[Link] is not a substitute for a task group when you need cancellation semantics.
[Link] (3.11+) is what you actually want most of the time. Forgetting to await a
coroutine returns a coroutine object and silently does nothing — Python only warns at GC
time.
Random Python tips
[Link](key, default) avoids KeyError. [Link](list) is cleaner than
checking-and-appending. enumerate(x, start=1) for 1-indexed loops. zip(*matrix) transposes a
matrix. [Link] (3.10+) gives you sliding pairs without manual indexing.
Things that bit me
Mutable default arguments. def f(x=[]) — that list is shared across all calls. Use None and
check inside. Late binding in lambdas inside a loop: every lambda captures the same loop
variable. Use a default argument to bind early: lambda x=i: x.
Last week I spent two hours debugging a cache that was 'returning the wrong values' when
the actual bug was a mutable default in a helper function written six months ago. The lesson
keeps not sticking.