The 5 Python Features I Wish I'd Known 2 Years Earlier
TL;DR: Python rewards depth. These five features stayed hidden from me longer than they should have — each one collapses code that I used to write the long way.
1. functools.singledispatch
Generic functions in Python with proper type-based dispatch. Beats long if/elif chains for handling multiple input types.
from functools import singledispatch
@singledispatch
def render(obj):
raise NotImplementedError(f"can't render {type(obj)}")
@render.register
def _(obj: str):
return f"<p>{obj}</p>"
@render.register
def _(obj: list):
return "<ul>" + "".join(f"<li>{render(x)}</li>" for x in obj) + "</ul>"
@render.register
def _(obj: dict):
return "<dl>" + "".join(f"<dt>{k}</dt><dd>{render(v)}</dd>" for k, v in obj.items()) + "</dl>"
print(render(["a", "b", {"x": "y"}]))
2. dataclasses with slots and frozen
@dataclass(slots=True, frozen=True) gives you immutability + memory efficiency in one decorator. No more __slots__ boilerplate.
from dataclasses import dataclass
@dataclass(slots=True, frozen=True)
class Point:
x: float
y: float
p = Point(1.0, 2.0)
# p.x = 5 # FrozenInstanceError
3. Walrus operator for parsing loops
The := assignment expression eliminates the read-twice pattern in while loops.
# before
chunk = f.read(4096)
while chunk:
process(chunk)
chunk = f.read(4096)
# after
while chunk := f.read(4096):
process(chunk)
4. structural pattern matching
match/case isn't just a switch. It destructures.
def handle(event):
match event:
case {"type": "user.signup", "email": email}:
send_welcome(email)
case {"type": "order.placed", "id": oid, "total": total} if total > 100:
flag_for_review(oid)
case {"type": event_type}:
log.info("ignored event %s", event_type)
case _:
log.warning("malformed event: %r", event)
5. contextlib.suppress
try/except: pass is a smell. contextlib.suppress says the same thing in one line and tells the reader you mean it.
from contextlib import suppress
with suppress(FileNotFoundError):
os.remove("/tmp/maybe-exists")