Claude Code for weakref: Weak References in Python — Claude Skills 360 Blog
Blog / AI / Claude Code for weakref: Weak References in Python
AI

Claude Code for weakref: Weak References in Python

Published: July 28, 2028
Read time: 5 min read
By: Claude Skills 360

Python’s weakref module creates references that don’t prevent garbage collection. import weakref. ref: r = weakref.ref(obj) — creates a weak reference; r() returns obj or None if collected. proxy: p = weakref.proxy(obj) — transparent proxy; raises ReferenceError if referent collected. WeakValueDictionary: weakref.WeakValueDictionary() — values are weak refs; entries auto-removed when values are collected. WeakKeyDictionary: weakref.WeakKeyDictionary() — keys are weak refs. WeakSet: weakref.WeakSet() — set with weak element references. finalize: weakref.finalize(obj, callback, *args) — calls callback when obj is collected; .alive property; .cancel() to unregister; .detach() to get obj back. ref callback: weakref.ref(obj, callback) — callback(ref) called on collection. getweakrefcount: weakref.getweakrefcount(obj) — number of weak refs. getweakrefs: weakref.getweakrefs(obj) — list of weak refs. WeakMethod: weakref.WeakMethod(bound_method) — weak ref to a bound method without keeping instance alive. Weakref-able types: user-defined classes, most builtins not weakref-able (int, str, tuple). __weakref__ slot: add __slots__ = ("__weakref__",) to slotted classes. Claude Code generates object caches, observer registries, event buses, and resource lifecycle managers.

CLAUDE.md for weakref

## weakref Stack
- Stdlib: import weakref
- Ref:      r = weakref.ref(obj); obj_or_none = r()
- Proxy:    p = weakref.proxy(obj)  — transparent but raises ReferenceError if dead
- Cache:    weakref.WeakValueDictionary()  — auto-evicts collected values
- Cleanup:  weakref.finalize(obj, fn, *args)  — runs fn when obj dies
- Observer: store weakref.ref(callback_obj) not the object itself

weakref Object Lifecycle Pipeline

# app/weakutil.py — weak refs, caches, observer, finalize, WeakMethod
from __future__ import annotations

import gc
import weakref
from collections.abc import Callable
from dataclasses import dataclass, field
from typing import Any, Generic, Iterator, TypeVar

T   = TypeVar("T")
K   = TypeVar("K")
V   = TypeVar("V")


# ─────────────────────────────────────────────────────────────────────────────
# 1. Weak reference helpers
# ─────────────────────────────────────────────────────────────────────────────

def weak_ref(obj: T, callback: Callable | None = None) -> "weakref.ref[T]":
    """
    Create a weak reference to obj with an optional dead-notification callback.

    Example:
        r = weak_ref(some_object, lambda ref: print("collected"))
        obj_or_none = r()
    """
    if callback is not None:
        return weakref.ref(obj, callback)
    return weakref.ref(obj)


def deref(ref: "weakref.ref[T]", default: T | None = None) -> T | None:
    """
    Dereference a weak ref; return default if the referent has been collected.

    Example:
        obj = deref(r, default=None)
        if obj is None:
            print("object is gone")
    """
    obj = ref()
    return obj if obj is not None else default


def is_alive(ref: "weakref.ref") -> bool:
    """Return True if the referent is still alive."""
    return ref() is not None


def safe_proxy(obj: T) -> Any:
    """
    Return a weakref proxy to obj.
    Accessing attributes through the proxy when obj is collected raises ReferenceError.

    Example:
        p = safe_proxy(resource)
        p.do_work()  # transparent; raises ReferenceError if resource collected
    """
    return weakref.proxy(obj)


# ─────────────────────────────────────────────────────────────────────────────
# 2. Weak value cache
# ─────────────────────────────────────────────────────────────────────────────

class WeakCache(Generic[K, V]):
    """
    A dictionary-like cache whose values are held by weak references.
    Entries are automatically removed when their values are garbage collected.

    Example:
        cache = WeakCache()
        cache["img_123"] = load_image("123.png")
        # Once no other references to the image exist, it's evicted automatically.
    """

    def __init__(self) -> None:
        self._store: weakref.WeakValueDictionary[K, V] = weakref.WeakValueDictionary()

    def __setitem__(self, key: K, value: V) -> None:
        self._store[key] = value

    def __getitem__(self, key: K) -> V:
        return self._store[key]

    def get(self, key: K, default: V | None = None) -> V | None:
        return self._store.get(key, default)

    def __contains__(self, key: object) -> bool:
        return key in self._store

    def __delitem__(self, key: K) -> None:
        del self._store[key]

    def __len__(self) -> int:
        return len(self._store)

    def keys(self):
        return self._store.keys()

    def values(self):
        return self._store.values()

    def items(self):
        return self._store.items()

    def setdefault(self, key: K, factory: Callable[[], V]) -> V:
        """
        Return cached value for key; call factory() and cache it if missing.

        Example:
            img = cache.setdefault("logo", lambda: load_image("logo.png"))
        """
        obj = self._store.get(key)
        if obj is None:
            obj = factory()
            self._store[key] = obj
        return obj

    def stats(self) -> dict[str, int]:
        return {"size": len(self._store)}


# ─────────────────────────────────────────────────────────────────────────────
# 3. Finalize / cleanup callbacks
# ─────────────────────────────────────────────────────────────────────────────

class ResourceGuard:
    """
    Attach a cleanup callback to an object that fires when the object is collected.
    Works even if the object's __del__ method is not defined.

    Example:
        conn = open_db_connection()
        guard = ResourceGuard(conn, close_db_connection, conn_id)
        # When conn is collected, close_db_connection(conn_id) is called.
    """

    def __init__(self, obj: Any, cleanup: Callable, *args: Any) -> None:
        self._finalizer = weakref.finalize(obj, cleanup, *args)

    @property
    def alive(self) -> bool:
        """True if the guarded object is still alive."""
        return self._finalizer.alive

    def cancel(self) -> None:
        """Cancel the cleanup callback (e.g., cleanup already done manually)."""
        self._finalizer.cancel()

    def __repr__(self) -> str:
        return f"ResourceGuard(alive={self.alive})"


def on_collect(obj: T, callback: Callable[[str], None], label: str = "") -> weakref.finalize:
    """
    Register a callback that fires with label when obj is garbage collected.

    Example:
        on_collect(session, lambda lbl: print(f"Session {lbl} ended"), session.id)
    """
    return weakref.finalize(obj, callback, label)


# ─────────────────────────────────────────────────────────────────────────────
# 4. Observer / event bus with weak callbacks
# ─────────────────────────────────────────────────────────────────────────────

class WeakObserverList:
    """
    A list of weakly-referenced observer callables.
    Dead observers are silently dropped during notification.

    Example:
        obs = WeakObserverList()

        class MyListener:
            def on_event(self, data):
                print("event:", data)

        listener = MyListener()
        obs.add(listener.on_event)
        obs.notify("hello")          # prints "event: hello"
        del listener
        obs.notify("after gc")       # silently dropped — no error
    """

    def __init__(self) -> None:
        self._refs: list[weakref.ref | weakref.WeakMethod] = []

    def add(self, callback: Callable) -> None:
        """Register a callback. Uses WeakMethod for bound methods."""
        import inspect
        if inspect.ismethod(callback):
            ref = weakref.WeakMethod(callback)
        else:
            ref = weakref.ref(callback)
        self._refs.append(ref)

    def remove(self, callback: Callable) -> None:
        """Unregister a callback (best-effort)."""
        self._refs = [r for r in self._refs if r() is not None and r() != callback]

    def notify(self, *args: Any, **kwargs: Any) -> int:
        """
        Call all live observers with *args/**kwargs.
        Returns count of observers notified.
        """
        live: list[weakref.ref | weakref.WeakMethod] = []
        notified = 0
        for ref in self._refs:
            cb = ref()
            if cb is not None:
                live.append(ref)
                cb(*args, **kwargs)
                notified += 1
        self._refs = live
        return notified

    def __len__(self) -> int:
        self._refs = [r for r in self._refs if r() is not None]
        return len(self._refs)


class WeakEventBus:
    """
    Simple event bus where subscribers are held by weak references.

    Example:
        bus = WeakEventBus()

        class Handler:
            def handle(self, payload):
                print("got:", payload)

        h = Handler()
        bus.subscribe("user.created", h.handle)
        bus.publish("user.created", {"id": 1})
    """

    def __init__(self) -> None:
        self._channels: dict[str, WeakObserverList] = {}

    def subscribe(self, event: str, callback: Callable) -> None:
        if event not in self._channels:
            self._channels[event] = WeakObserverList()
        self._channels[event].add(callback)

    def unsubscribe(self, event: str, callback: Callable) -> None:
        if event in self._channels:
            self._channels[event].remove(callback)

    def publish(self, event: str, *args: Any, **kwargs: Any) -> int:
        """Publish event; return number of live subscribers notified."""
        channel = self._channels.get(event)
        if channel is None:
            return 0
        return channel.notify(*args, **kwargs)

    def subscriber_counts(self) -> dict[str, int]:
        return {ev: len(obs) for ev, obs in self._channels.items()}


# ─────────────────────────────────────────────────────────────────────────────
# 5. WeakKeyDictionary for attribute sidecars
# ─────────────────────────────────────────────────────────────────────────────

class SidecarStore(Generic[K, V]):
    """
    Associate extra data with objects without modifying them or keeping them alive.
    Uses WeakKeyDictionary: when the object is collected, its sidecar data is too.

    Example:
        meta = SidecarStore()
        meta[request] = {"start_time": time.time(), "user_id": 42}
        print(meta.get(request))
        del request  # sidecar auto-removed
    """

    def __init__(self) -> None:
        self._store: weakref.WeakKeyDictionary[K, V] = weakref.WeakKeyDictionary()

    def __setitem__(self, obj: K, value: V) -> None:
        self._store[obj] = value

    def __getitem__(self, obj: K) -> V:
        return self._store[obj]

    def get(self, obj: K, default: V | None = None) -> V | None:
        return self._store.get(obj, default)

    def __contains__(self, obj: object) -> bool:
        return obj in self._store

    def __delitem__(self, obj: K) -> None:
        del self._store[obj]

    def __len__(self) -> int:
        return len(self._store)


# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    print("=== weakref demo ===")

    print("\n--- basic weak_ref / deref ---")
    class Node:
        def __init__(self, val: int) -> None:
            self.val = val
        def __repr__(self) -> str:
            return f"Node({self.val})"

    n = Node(42)
    r = weak_ref(n)
    print(f"  alive: {is_alive(r)}  deref: {deref(r)}")
    del n
    gc.collect()
    print(f"  after del: alive={is_alive(r)}  deref={deref(r)}")

    print("\n--- WeakCache ---")
    cache: WeakCache[str, Node] = WeakCache()
    a = Node(1)
    b = Node(2)
    cache["a"] = a
    cache["b"] = b
    print(f"  size: {len(cache)}  'a' in cache: {'a' in cache}")
    del a
    gc.collect()
    print(f"  after del a: size={len(cache)}  'a' in cache={'a' in cache}")

    print("\n--- ResourceGuard / finalize ---")
    collected_labels: list[str] = []

    def on_gone(label: str) -> None:
        collected_labels.append(label)

    resource = Node(99)
    guard = ResourceGuard(resource, on_gone, "node-99")
    print(f"  guard.alive before del: {guard.alive}")
    del resource
    gc.collect()
    print(f"  guard.alive after del: {guard.alive}")
    print(f"  collected_labels: {collected_labels}")

    print("\n--- WeakObserverList ---")
    results: list[str] = []

    class Listener:
        def __init__(self, name: str) -> None:
            self.name = name
        def on_event(self, data: str) -> None:
            results.append(f"{self.name}:{data}")

    obs = WeakObserverList()
    l1 = Listener("L1")
    l2 = Listener("L2")
    obs.add(l1.on_event)
    obs.add(l2.on_event)
    obs.notify("ping")
    print(f"  after notify: {results}")
    del l1
    gc.collect()
    results.clear()
    count = obs.notify("ping2")
    print(f"  after del L1: notified={count}  results={results}")

    print("\n--- WeakEventBus ---")
    bus = WeakEventBus()
    payloads: list[Any] = []

    class Sub:
        def handle(self, data: Any) -> None:
            payloads.append(data)

    sub = Sub()
    bus.subscribe("order.paid", sub.handle)
    n1 = bus.publish("order.paid", {"order_id": 1})
    print(f"  published to {n1} subscriber(s): {payloads}")
    del sub
    gc.collect()
    n2 = bus.publish("order.paid", {"order_id": 2})
    print(f"  after sub deleted: notified={n2}  payloads unchanged={payloads}")

    print("\n--- SidecarStore ---")
    sidecar: SidecarStore[Node, dict] = SidecarStore()
    obj1 = Node(10)
    obj2 = Node(20)
    sidecar[obj1] = {"tag": "first"}
    sidecar[obj2] = {"tag": "second"}
    print(f"  sidecar[obj1]: {sidecar[obj1]}")
    del obj1
    gc.collect()
    print(f"  after del obj1: len={len(sidecar)}")

    print("\n=== done ===")

For the gc alternative — Python’s gc module (also stdlib) controls the cyclic garbage collector directly: gc.collect() forces a collection cycle, gc.get_referrers(obj) returns all objects holding a reference to obj, gc.is_tracked(obj) checks gc tracking, and gc.callbacks lets you hook collection events; weakref handles reference strength rather than collection timing — use gc when you need to diagnose reference cycles, force immediate reclamation in memory-sensitive hot paths, or hook pre/post-collection events, weakref for designing cache and observer structures where you want Python’s normal collection to remove entries automatically. For the functools.lru_cache alternative — functools.lru_cache (also stdlib) caches the n most recent call results using strong references with a bounded LRU eviction policy; results stay alive until evicted by size pressure; weakref.WeakValueDictionary cache keeps results alive only as long as some other code holds a reference, giving zero size overhead for cold entries — use lru_cache when results should be kept warm between calls and memory pressure is managed by a fixed capacity, WeakValueDictionary cache when objects are large, already held elsewhere by the caller, and you want the cache to act as a free lookup rather than a retention mechanism. The Claude Skills 360 bundle includes weakref skill sets covering weak_ref()/deref()/is_alive()/safe_proxy() reference helpers, WeakCache generic weak-value cache with setdefault() factory, ResourceGuard/on_collect() finalize-based cleanup, WeakObserverList/WeakEventBus observer pattern with automatic dead-subscriber pruning, and SidecarStore WeakKeyDictionary attribute sidecar. Start with the free tier to try object lifecycle management and weakref pipeline code generation.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free