Документация Python неофициальный перевод

weakref.md

245 строк · 21.3 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.1/library/weakref.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 8.9. `weakref` – Слабые ссылки89Модуль `weakref` позволяет программисту Python создавать *слабые ссылки* на объекты.1011В дальнейшем под термином *referent* понимается объект, на который указывает слабая ссылка.1213Слабая ссылка на объект не может сама по себе поддерживать его существование: когда единственными оставшимися ссылками на объект являются слабые ссылки, [*сборщик мусора*](https://python-all.ru/3.1/glossary.html#term-garbage-collection) может уничтожить этот объект и использовать его память для других целей. Основное применение слабых ссылок – реализация кэшей или отображений, содержащих крупные объекты, когда нежелательно, чтобы большой объект оставался в памяти только из-за того, что он присутствует в кэше или отображении.1415Например, если у вас есть несколько крупных объектов бинарных изображений, вы можете захотеть связать с каждым из них имя. Если использовать словарь Python для отображения имён на изображения или изображений на имена, объекты изображений будут оставаться в памяти только потому, что они фигурируют как значения или ключи в словарях. Классы [`WeakKeyDictionary`](https://python-all.ru/3.1/library/weakref.html#weakref.WeakKeyDictionary) и [`WeakValueDictionary`](https://python-all.ru/3.1/library/weakref.html#weakref.WeakValueDictionary) из модуля `weakref` представляют собой альтернативу: они используют слабые ссылки для создания отображений, которые не поддерживают объекты в памяти только из-за их присутствия в этих отображениях. Если, например, объект изображения является значением в [`WeakValueDictionary`](https://python-all.ru/3.1/library/weakref.html#weakref.WeakValueDictionary), то, когда последними оставшимися ссылками на этот объект будут слабые ссылки, хранящиеся в слабых отображениях, сборщик мусора сможет освободить объект, а соответствующие записи в слабых отображениях будут просто удалены.1617[`WeakKeyDictionary`](https://python-all.ru/3.1/library/weakref.html#weakref.WeakKeyDictionary) и [`WeakValueDictionary`](https://python-all.ru/3.1/library/weakref.html#weakref.WeakValueDictionary) используют слабые ссылки в своей реализации, устанавливая функции обратного вызова на слабые ссылки, которые уведомляют слабые словари, когда ключ или значение были освобождены сборщиком мусора. Класс [`WeakSet`](https://python-all.ru/3.1/library/weakref.html#weakref.WeakSet) реализует интерфейс [`set`](https://python-all.ru/3.1/library/stdtypes.html#set), но хранит слабые ссылки на свои элементы, подобно тому, как это делает [`WeakKeyDictionary`](https://python-all.ru/3.1/library/weakref.html#weakref.WeakKeyDictionary).1819Большинству программ достаточно использовать один из этих типов слабых контейнеров – обычно нет необходимости создавать собственные слабые ссылки напрямую. Низкоуровневые механизмы, используемые в реализации слабых словарей, предоставляются модулем `weakref` для опытных пользователей.2021> **Примечание**22>23> Слабые ссылки на объект очищаются до вызова [`__del__()`](https://python-all.ru/3.1/reference/datamodel.html#object.__del__) этого объекта, чтобы колбэк слабой ссылки (если он есть) застал объект ещё живым.2425Не все объекты могут иметь слабые ссылки; к тем, которые могут, относятся экземпляры классов, функции, написанные на Python (но не на C), методы экземпляров, множества, frozenset, некоторые [*файловые объекты*](https://python-all.ru/3.1/glossary.html#term-file-object), [*генераторы*](https://python-all.ru/3.1/glossary.html#term-generator), объекты типов, сокеты, массивы, деки и объекты шаблонов регулярных выражений.2627Некоторые встроенные типы, такие как [`list`](https://python-all.ru/3.1/library/functions.html#list) и [`dict`](https://python-all.ru/3.1/library/stdtypes.html#dict), напрямую не поддерживают слабые ссылки, но могут добавить поддержку через создание подклассов:2829```python30class Dict(dict):31    pass3233obj = Dict(red=1, green=2, blue=3)   # этот объект поддерживает слабые ссылки34```3536Другие встроенные типы, такие как [`tuple`](https://python-all.ru/3.1/library/functions.html#tuple) и [`int`](https://python-all.ru/3.1/library/functions.html#int), не поддерживают слабые ссылки даже при создании подклассов (это деталь реализации и может отличаться в разных реализациях Python.).3738Расширяемые типы можно легко научить поддерживать слабые ссылки; см. [*Поддержка слабых ссылок*](https://python-all.ru/3.1/extending/newtypes.html#weakref-support).3940#### `class weakref.ref(object[, callback])`4142Возвращает слабую ссылку на *object*. Исходный объект можно получить, вызвав объект ссылки, если референт ещё жив; если референт больше не жив, вызов объекта ссылки вернёт [`None`](https://python-all.ru/3.1/library/constants.html#None). Если указан *колбэк* и он не равен [`None`](https://python-all.ru/3.1/library/constants.html#None), и возвращённый объект слабой ссылки ещё существует, то колбэк будет вызван, когда объект будет финализирован; объект слабой ссылки будет передан колбэку как единственный параметр; референт больше не будет доступен.4344Допускается создание нескольких слабых ссылок на один и тот же объект. Колбэки, зарегистрированные для каждой слабой ссылки, будут вызываться от самого недавно зарегистрированного колбэка до самого старого.4546Исключения, возбуждённые колбэком, будут зафиксированы в стандартном выводе ошибок, но не могут быть распространены; они обрабатываются точно так же, как исключения, возбуждённые из метода [`__del__()`](https://python-all.ru/3.1/reference/datamodel.html#object.__del__) объекта.4748Слабые ссылки являются [*хешируемыми*](https://python-all.ru/3.1/glossary.html#term-hashable), если *object* хешируем. Они сохраняют своё хеш-значение даже после удаления *object*. Если [`hash()`](https://python-all.ru/3.1/library/functions.html#hash) вызывается впервые только после удаления *object*, вызов возбудит [`TypeError`](https://python-all.ru/3.1/library/exceptions.html#TypeError).4950Слабые ссылки поддерживают проверку на равенство, но не на упорядочивание. Если референты ещё живы, две ссылки имеют то же отношение равенства, что и их референты (независимо от *колбэк*). Если любой из референтов был удалён, ссылки равны только в том случае, если объекты ссылок являются одним и тем же объектом.5152Это тип, который можно наследовать, а не фабричная функция.5354#### `weakref.proxy(object[, callback])`5556Return a proxy to5758*object*5960which uses a weak reference. This supports use of the proxy in most contexts instead of requiring the explicit dereferencing used with weak reference objects. The returned object will have a type of either6162`ProxyType`6364or6566`CallableProxyType`6768, depending on whether6970*object*7172is callable. Proxy objects are not7374[*hashable*](https://python-all.ru/3.1/glossary.html#term-hashable)7576regardless of the referent; this avoids a number of problems related to their fundamentally mutable nature, and prevent their use as dictionary keys.7778*callback*7980is the same as the parameter of the same name to the8182[`ref()`](https://python-all.ru/3.1/library/weakref.html#weakref.ref)8384function.8586#### `weakref.getweakrefcount(object)`8788Возвращает количество слабых ссылок и прокси, которые ссылаются на8990*object*9192.9394#### `weakref.getweakrefs(object)`9596Возвращает список всех объектов слабых ссылок и прокси, которые ссылаются на9798*object*99100.101102#### `class weakref.WeakKeyDictionary([dict])`103104Класс отображения, который хранит слабые ссылки на ключи. Записи словаря будут удалены, когда на ключ больше не останется сильных ссылок. Это можно использовать для связывания дополнительных данных с объектом, принадлежащим другим частям приложения, без добавления атрибутов к этим объектам. Это особенно полезно для объектов, которые переопределяют доступ к атрибутам.105106> **Примечание**107>108> Предостережение: Поскольку [`WeakKeyDictionary`](https://python-all.ru/3.1/library/weakref.html#weakref.WeakKeyDictionary) построен на основе словаря Python, его размер не должен изменяться при итерации. Это может быть трудно обеспечить для [`WeakKeyDictionary`](https://python-all.ru/3.1/library/weakref.html#weakref.WeakKeyDictionary), потому что действия, выполняемые программой во время итерации, могут привести к тому, что элементы словаря исчезнут «магическим образом» (как побочный эффект сборки мусора).109110Объекты [`WeakKeyDictionary`](https://python-all.ru/3.1/library/weakref.html#weakref.WeakKeyDictionary) имеют следующие дополнительные методы. Они предоставляют прямой доступ к внутренним ссылкам. Ссылки не гарантированно являются «живыми» на момент их использования, поэтому результат вызова ссылок необходимо проверять перед использованием. Это можно использовать, чтобы избежать создания ссылок, которые заставят сборщик мусора хранить ключи дольше, чем необходимо.111112#### `WeakKeyDictionary.keyrefs()`113114Возвращает итератор по слабым ссылкам на ключи.115116#### `class weakref.WeakValueDictionary([dict])`117118Класс отображения, который хранит слабые ссылки на значения. Записи словаря будут удалены, когда на значение больше не будет сильных ссылок.119120> **Примечание**121>122> Предостережение: Поскольку [`WeakValueDictionary`](https://python-all.ru/3.1/library/weakref.html#weakref.WeakValueDictionary) построен на основе словаря Python, его размер не должен изменяться при итерации. Это может быть трудно обеспечить для [`WeakValueDictionary`](https://python-all.ru/3.1/library/weakref.html#weakref.WeakValueDictionary), потому что действия, выполняемые программой во время итерации, могут привести к тому, что элементы словаря исчезнут «магическим образом» (как побочный эффект сборки мусора).123124Объекты [`WeakValueDictionary`](https://python-all.ru/3.1/library/weakref.html#weakref.WeakValueDictionary) имеют следующие дополнительные методы. У этих методов такие же проблемы, как и у метода `keyrefs()` объектов [`WeakKeyDictionary`](https://python-all.ru/3.1/library/weakref.html#weakref.WeakKeyDictionary).125126#### `WeakValueDictionary.valuerefs()`127128Возвращает итератор по слабым ссылкам на значения.129130#### `class weakref.WeakSet([elements])`131132Класс множества, который хранит слабые ссылки на свои элементы. Элемент будет удален, когда на него больше не останется сильных ссылок.133134#### `weakref.ReferenceType`135136Объект типа для объектов слабых ссылок.137138#### `weakref.ProxyType`139140Объект типа для прокси-объектов, которые не являются вызываемыми.141142#### `weakref.CallableProxyType`143144Объект типа для прокси вызываемых объектов.145146#### `weakref.ProxyTypes`147148Последовательность, содержащая все объекты типа для прокси. Это упрощает проверку, является ли объект прокси, без необходимости называть оба типа прокси.149150#### `exception weakref.ReferenceError`151152Исключение, возникающее при использовании прокси-объекта, когда исходный объект уже собран сборщиком мусора. Это то же самое, что и стандартное исключение153154[`ReferenceError`](https://python-all.ru/3.1/library/exceptions.html#ReferenceError)155156.157158> **См. также**159>160> **[**PEP 0205**](https://python-all.ru/3.1/library/weakref.html) – Слабые ссылки**161>162> Предложение и обоснование этой возможности, включая ссылки на более ранние реализации и информацию о подобных возможностях в других языках.163164## 8.9.1. Объекты слабых ссылок165166Объекты слабых ссылок не имеют атрибутов или методов, но позволяют получить референт, если он ещё существует, вызвав объект слабой ссылки:167168```python169>>> import weakref170>>> class Object:171...     pass172...173>>> o = Object()174>>> r = weakref.ref(o)175>>> o2 = r()176>>> o is o2177True178```179180Если объект ссылки больше не существует, вызов объекта ссылки возвращает [`None`](https://python-all.ru/3.1/library/constants.html#None):181182```python183>>> del o, o2184>>> print(r())185None186```187188Проверять, жива ли ещё слабая ссылка, следует с помощью выражения `ref() is not None`. Обычно код приложения, которому нужно использовать объект ссылки, должен следовать такому шаблону:189190```python191# r – объект слабой ссылки192o = r()193if o is None:194    # объект был собран сборщиком мусора195    print("Object has been deallocated; can't frobnicate.")196else:197    print("Object is still live!")198    o.do_something_useful()199```200201Использование отдельной проверки «живучести» создаёт состояния гонки в многопоточных приложениях; другой поток может привести к инвалидации слабой ссылки до того, как она будет вызвана; идиома, показанная выше, безопасна как в многопоточных, так и в однопоточных приложениях.202203Специализированные версии объектов [`ref`](https://python-all.ru/3.1/library/weakref.html#weakref.ref) можно создавать с помощью наследования. Это используется в реализации [`WeakValueDictionary`](https://python-all.ru/3.1/library/weakref.html#weakref.WeakValueDictionary) для уменьшения накладных расходов памяти на каждую запись в отображении. Это может быть особенно полезно для связывания дополнительной информации со ссылкой, а также для добавления дополнительной обработки при вызовах получения объекта ссылки.204205В этом примере показано, как подкласс [`ref`](https://python-all.ru/3.1/library/weakref.html#weakref.ref) можно использовать для хранения дополнительной информации об объекте и изменения значения, возвращаемого при доступе к объекту ссылки:206207```python208import weakref209210class ExtendedRef(weakref.ref):211    def __init__(self, ob, callback=None, **annotations):212        super(ExtendedRef, self).__init__(ob, callback)213        self.__counter = 0214        for k, v in annotations.items():215            setattr(self, k, v)216217    def __call__(self):218        """Возвращает пару, содержащую объект и количество219        вызовов ссылки.220        """221        ob = super(ExtendedRef, self).__call__()222        if ob is not None:223            self.__counter += 1224            ob = (ob, self.__counter)225        return ob226```227228## 8.9.2. Пример229230Этот простой пример показывает, как приложение может использовать идентификаторы объектов для получения объектов, которые оно уже видело ранее. Идентификаторы объектов затем можно использовать в других структурах данных, не заставляя объекты оставаться живыми, но при этом объекты всё ещё можно получить по идентификатору, если они живы.231232```python233import weakref234235_id2obj_dict = weakref.WeakValueDictionary()236237def remember(obj):238    oid = id(obj)239    _id2obj_dict[oid] = obj240    return oid241242def id2obj(oid):243    return _id2obj_dict[oid]244```245