Python Advanced Topics
Overview of advanced Python — context managers, memory management, and links to dedicated chapters on decorators, generators, regex, and databases.
This chapter covers advanced Python features. Several topics have dedicated deep-dive pages — follow the links for comprehensive coverage.
Related Deep-Dive Chapters
| Topic | Chapter |
|---|---|
| Iterators & Generators | Iterators & Generators |
| Decorators | Decorators |
| Regular Expressions | Regular Expressions |
| Databases | Working with Databases |
| Type Hints | Type Hints |
| Async | Async Programming |
| Metaprogramming | Metaprogramming |
Context Managers
Context managers guarantee setup and cleanup — most commonly for files, locks, and database connections:
with open("data.txt") as f:
content = f.read()
# File automatically closed, even if an exception occurred
Custom Context Managers
Using a class:
class Timer:
def __enter__(self):
import time
self.start = time.perf_counter()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
import time
elapsed = time.perf_counter() - self.start
print(f"Elapsed: {elapsed:.4f}s")
return False # don't suppress exceptions
with Timer():
sum(range(1_000_000))
Using @contextmanager:
from contextlib import contextmanager
@contextmanager
def temporary_file(content):
import tempfile, os
path = tempfile.mktemp(suffix=".txt")
with open(path, "w") as f:
f.write(content)
try:
yield path
finally:
os.remove(path)
with temporary_file("test data") as path:
with open(path) as f:
print(f.read())
contextlib Utilities
from contextlib import suppress, redirect_stdout
import io
# Suppress specific exceptions
with suppress(FileNotFoundError):
os.remove("nonexistent.txt")
# Capture stdout
buffer = io.StringIO()
with redirect_stdout(buffer):
print("captured")
print(buffer.getvalue()) # "captured\n"
Memory Management
Python uses reference counting plus a generational garbage collector for cycles:
import sys
a = [1, 2, 3]
print(sys.getrefcount(a)) # reference count (includes temp ref from getrefcount)
del a # decrements count; memory freed when count hits 0
Weak References
import weakref
class Cache:
def __init__(self):
self._store = {}
def get(self, key, factory):
obj = self._store.get(key)
if obj is None or obj() is None:
instance = factory()
self._store[key] = weakref.ref(instance)
return instance
return obj()
__slots__ for Memory Efficiency
class Point:
__slots__ = ("x", "y")
def __init__(self, x, y):
self.x = x
self.y = y
Instances use ~40% less memory than regular classes — useful when creating millions of objects.
The dataclasses Module
Reduce boilerplate for data-holding classes:
from dataclasses import dataclass, field
from typing import list
@dataclass
class Product:
name: str
price: float
tags: list[str] = field(default_factory=list)
@property
def display_price(self):
return f"${self.price:.2f}"
p = Product("Widget", 9.99, tags=["sale"])
print(p) # Product(name='Widget', price=9.99, tags=['sale'])
@dataclass auto-generates __init__, __repr__, __eq__, and more.
The enum Module
Define named constants:
from enum import Enum, auto
class Status(Enum):
PENDING = "pending"
ACTIVE = "active"
CLOSED = "closed"
class Color(Enum):
RED = auto()
GREEN = auto()
BLUE = auto()
print(Status.ACTIVE) # Status.ACTIVE
print(Status.ACTIVE.value) # "active"
Walrus Operator (:=)
Assign and use a value in one expression (Python 3.8+):
# Before
data = read_file()
if data:
process(data)
# With walrus
if (data := read_file()):
process(data)
# In comprehensions
results = [y for x in inputs if (y := transform(x)) is not None]
These advanced features unlock cleaner, more efficient Python code. Explore the linked chapters for full coverage of each topic.