Вход на сайт

Просмотр новости

Найдите то, что Вас интересует

Store Extra Data for Objects in a WeakKeyDictionary

Дата публикации: 12-07-2026 18:19:44



Основное содержимое страницы с новостью.

2026-06-27A filing cabinet, strong and sturdy but with weak keys.

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:

  • The object may not allow arbitrary attributes, such as for built-in types like dict or slotted classes.
  • Attribute names can collide across use cases. Defences against this include using a long, verbose attribute name and prefixing it with an underscore, but they don’t provide any guarantees.
  • Attributes may confusingly appear in other code paths that expose all attributes on the object, such as where 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.

  1. 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.

  2. 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”.

Fin

May your code be strong even when your references are weak,

—Adam


Read my book Boost Your Git DX to Git better.


One summary email a week, no spam, I pinky promise.

Related posts:

Tags: python

Схожие новости

#Наименование новостиТональностьИнформативностьДата публикации
1Find All Instances of a Class With gc.get_objects()01002-08-2026
2Gleam for Python Programmers01019-07-2026
3What Every Python Developer Should Know About the CPython ABI01019-07-2026
4django-orjson - orjson, a Rusty replacement for json021.1119-07-2026
5Worldwide Data Storage0509-07-2026
6fapost/support08.2603-08-2026
7python-pkcs11 0.9.50510-07-2026
8Map Arrays- Map of Items0507-05-2026
9Pickle-десериализация в Python: как одна строка кода может привести к выполнению произвольных команд015.6210-07-2026

Классификация: . Схожих патентов: 0. Схожих новостей: 9. Тональность: 0. Информативность: 10. Источник: pythondigest.ru.