ㅤ

In several programs, I’ve wanted to solve the problem of associating extra data with an object. For example, in django-upgrade, the individual “fixer” functions often want to store extra data per visited ast.Module object.
A common pattern in Python is to store the data in an extra attribute directly on the object, like module._all_used_names = .... However, this approach has some downsides:
dict or slotted classes.vars() is used.Here’s a pattern that I’ve used to (mostly) avoid these issues:
import ast from weakref import WeakKeyDictionary used_names_cache: WeakKeyDictionary[ast.Module, frozenset[str]] = WeakKeyDictionary() def all_used_names(module: ast.Module) -> frozenset[str]: try: return used_names_cache[module] except KeyError: pass names = frozenset({name for name in ...}) # populate set used_names_cache[module] = names return names
The idea is to use a WeakKeyDictionary to store the extra data, keyed by the object. This special dictionary is keyed by the object, but because it uses a weak reference, if the object is no longer (strongly) referenced elsewhere, the dictionary entry will also be deleted. We get similar lookup performance (O(1)) to a typical attribute approach, but now the data lives “over here” rather than “over there” on the object itself, avoiding the downsides of direct attribute storage.
The object must satisfy two conditions: it must be hashable, and it must be weak-referenceable.
Classes are hashable by default in Python, unless they define a custom __eq__ method without a corresponding __hash__ method, so this requirement is usually met.
Most user-defined classes are weak-referenceable by default. Some built-in types, including int, str, list, and dict, cannot be weak-referenced directly. Slotted classes are not weak-referenceable by default, but can opt into it by adding __weakref__ in their __slots__ definition:
class Train: __slots__ = ("__weakref__", "wheels", "engine")
The extra slot expands the memory footprint slightly, but not above a vanilla class which has a hidden weakref “slot”.
Read my book Boost Your Git DX to Git better.
One summary email a week, no spam, I pinky promise.
Related posts:
SyntaxWarning: 'return' in a 'finally' blockBrokenPipeError when piping output to other commandsTags: python
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | Find All Instances of a Class With gc.get_objects() | 0 | 10 | 02-08-2026 |
| 2 | Gleam for Python Programmers | 0 | 10 | 19-07-2026 |
| 3 | What Every Python Developer Should Know About the CPython ABI | 0 | 10 | 19-07-2026 |
| 4 | django-orjson - orjson, a Rusty replacement for json | 0 | 21.11 | 19-07-2026 |
| 5 | Worldwide Data Storage | 0 | 5 | 09-07-2026 |
| 6 | fapost/support | 0 | 8.26 | 03-08-2026 |
| 7 | python-pkcs11 0.9.5 | 0 | 5 | 10-07-2026 |
| 8 | Map Arrays- Map of Items | 0 | 5 | 07-05-2026 |
| 9 | Pickle-десериализация в Python: как одна строка кода может привести к выполнению произвольных команд | 0 | 15.62 | 10-07-2026 |