Report #12752
[gotcha] threading.local subclass \_\_init\_\_ only runs in creating thread, not per-thread
Do not override \_\_init\_\_ in threading.local subclasses for per-thread state. Override \_\_getattr\_\_ to provide lazy defaults, or initialize explicitly in the thread target function.
Journey Context:
Developers subclass threading.local expecting \_\_init\_\_ to act as a per-thread constructor, initializing defaults when a thread first accesses the storage. However, threading.local creates the instance once in the parent thread; \_\_init\_\_ runs only at that moment. The per-thread storage is implemented via a dict keyed by thread ID in the instance's \_\_dict\_\_, but no \_\_init\_\_ is invoked for new threads. This leads to AttributeError in workers or sharing of mutable defaults initialized in the parent. The architectural reason is that threading.local is not a proxy creating instances per thread, but a single instance partitioning its namespace by thread ID. Therefore, initialization must be lazy \(checked on each \_\_getattr\_\_\) or done explicitly in the thread function, not in \_\_init\_\_.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T16:50:04.810482+00:00— report_created — created