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

weakref.md

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

1> **Источник:** https://python-all.ru/3.4/library/weakref.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 8.8. [`weakref`](https://python-all.ru/3.4/library/weakref.html#module-weakref) – Weak references89**Исходный код:** [Lib/weakref.py](https://python-all.ru/src/3.4/Lib/weakref.py)1011---1213Модуль [`weakref`](https://python-all.ru/3.4/library/weakref.html#module-weakref) позволяет программисту Python создавать *слабые ссылки* на объекты.1415В дальнейшем под термином *referent* понимается объект, на который указывает слабая ссылка.1617Слабой ссылки на объект недостаточно, чтобы сохранить объект живым: когда единственные оставшиеся ссылки на референт являются слабыми ссылками, [*сборщик мусора*](https://python-all.ru/3.4/glossary.html#term-garbage-collection) может уничтожить референт и использовать его память для других целей. Однако, пока объект фактически не уничтожен, слабая ссылка может вернуть объект, даже если на него нет сильных ссылок.1819Основное применение слабых ссылок – реализация кэшей или отображений, содержащих большие объекты, когда требуется, чтобы большой объект не оставался в живых только потому, что он присутствует в кэше или отображении.2021Например, если у вас есть несколько крупных объектов бинарных изображений, вы можете захотеть связать имя с каждым. Если вы используете словарь Python для сопоставления имён с изображениями или изображений с именами, объекты изображений будут оставаться живыми только потому, что они появляются в качестве значений или ключей в словарях. Классы [`WeakKeyDictionary`](https://python-all.ru/3.4/library/weakref.html#weakref.WeakKeyDictionary) и [`WeakValueDictionary`](https://python-all.ru/3.4/library/weakref.html#weakref.WeakValueDictionary), предоставляемые модулем [`weakref`](https://python-all.ru/3.4/library/weakref.html#module-weakref), являются альтернативой, использующей слабые ссылки для построения отображений, которые не хранят объекты живыми только потому, что они присутствуют в объектах отображения. Если, например, объект изображения является значением в [`WeakValueDictionary`](https://python-all.ru/3.4/library/weakref.html#weakref.WeakValueDictionary), то, когда последние оставшиеся ссылки на этот объект изображения будут слабыми ссылками, хранящимися в слабых отображениях, сборщик мусора может освободить объект, и соответствующие записи в слабых отображениях будут просто удалены.2223[`WeakKeyDictionary`](https://python-all.ru/3.4/library/weakref.html#weakref.WeakKeyDictionary) и [`WeakValueDictionary`](https://python-all.ru/3.4/library/weakref.html#weakref.WeakValueDictionary) используют слабые ссылки в своей реализации, устанавливая функции обратного вызова на слабые ссылки, которые уведомляют слабые словари, когда ключ или значение были освобождены сборщиком мусора. Класс [`WeakSet`](https://python-all.ru/3.4/library/weakref.html#weakref.WeakSet) реализует интерфейс [`set`](https://python-all.ru/3.4/library/stdtypes.html#set), но хранит слабые ссылки на свои элементы, подобно тому, как это делает [`WeakKeyDictionary`](https://python-all.ru/3.4/library/weakref.html#weakref.WeakKeyDictionary).2425[`finalize`](https://python-all.ru/3.4/library/weakref.html#weakref.finalize) предоставляет простой способ зарегистрировать функцию очистки, которая будет вызвана при сборке мусора объекта. Это проще в использовании, чем настройка функции обратного вызова на необработанную слабую ссылку, поскольку модуль автоматически гарантирует, что финализатор остаётся живым, пока объект не будет собран.2627Большинству программ достаточно использования одного из этих слабых типов контейнеров или [`finalize`](https://python-all.ru/3.4/library/weakref.html#weakref.finalize) – обычно нет необходимости создавать собственные слабые ссылки напрямую. Низкоуровневый механизм предоставляется модулем [`weakref`](https://python-all.ru/3.4/library/weakref.html#module-weakref) для продвинутого использования.2829Не все объекты могут быть слабо ссылаемыми; объекты, которые могут, включают экземпляры классов, функции, написанные на Python (но не на C), методы экземпляров, множества, неизменяемые множества, некоторые [*объекты файлов*](https://python-all.ru/3.4/glossary.html#term-file-object), [*генераторы*](https://python-all.ru/3.4/glossary.html#term-generator), объекты типов, сокеты, массивы, двусторонние очереди, объекты шаблонов регулярных выражений и объекты кода.3031Изменено в версии 3.2: Добавлена поддержка thread.lock, threading.Lock и объектов кода.3233Некоторые встроенные типы, такие как [`list`](https://python-all.ru/3.4/library/stdtypes.html#list) и [`dict`](https://python-all.ru/3.4/library/stdtypes.html#dict), напрямую не поддерживают слабые ссылки, но могут добавить поддержку через создание подклассов:3435```python36class Dict(dict):37    pass3839obj = Dict(red=1, green=2, blue=3)   # этот объект поддерживает слабые ссылки40```4142Другие встроенные типы, такие как [`tuple`](https://python-all.ru/3.4/library/stdtypes.html#tuple) и [`int`](https://python-all.ru/3.4/library/functions.html#int), не поддерживают слабые ссылки даже при создании подклассов (это деталь реализации и может отличаться в разных реализациях Python.).4344Расширяемые типы можно легко научить поддерживать слабые ссылки; см. [*Поддержка слабых ссылок*](https://python-all.ru/3.4/extending/newtypes.html#weakref-support).4546#### `class weakref.ref(object[, callback])`4748Возвращает слабую ссылку на *object*. Исходный объект можно получить, вызвав объект ссылки, если референт ещё жив; если референт больше не жив, вызов объекта ссылки вернёт [`None`](https://python-all.ru/3.4/library/constants.html#None). Если указан *колбэк* и он не равен [`None`](https://python-all.ru/3.4/library/constants.html#None), и возвращённый объект слабой ссылки ещё существует, то колбэк будет вызван, когда объект будет финализирован; объект слабой ссылки будет передан колбэку как единственный параметр; референт больше не будет доступен.4950Допускается создание нескольких слабых ссылок на один и тот же объект. Колбэки, зарегистрированные для каждой слабой ссылки, будут вызываться от самого недавно зарегистрированного колбэка до самого старого.5152Исключения, возбуждённые колбэком, будут зафиксированы в стандартном выводе ошибок, но не могут быть распространены; они обрабатываются точно так же, как исключения, возбуждённые из метода [`__del__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__del__) объекта.5354Слабые ссылки являются [*хешируемыми*](https://python-all.ru/3.4/glossary.html#term-hashable), если *object* хешируем. Они сохраняют своё хеш-значение даже после удаления *object*. Если [`hash()`](https://python-all.ru/3.4/library/functions.html#hash) вызывается впервые только после удаления *object*, вызов возбудит [`TypeError`](https://python-all.ru/3.4/library/exceptions.html#TypeError).5556Слабые ссылки поддерживают проверку на равенство, но не на упорядочивание. Если референты ещё живы, две ссылки имеют то же отношение равенства, что и их референты (независимо от *колбэк*). Если любой из референтов был удалён, ссылки равны только в том случае, если объекты ссылок являются одним и тем же объектом.5758Это тип, который можно наследовать, а не фабричная функция.5960#### `__callback__`6162Этот атрибут только для чтения возвращает колбэк, в данный момент связанный с weakref. Если колбэка нет или референт weakref больше не жив, то этот атрибут будет иметь значение `None`.6364Изменено в версии 3.4: Добавлен атрибут [`__callback__`](https://python-all.ru/3.4/library/weakref.html#weakref.ref.__callback__).6566#### `weakref.proxy(object[, callback])`6768Return a proxy to *object* which 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 either `ProxyType` or `CallableProxyType`, depending on whether *object* is callable. Proxy objects are not [*hashable*](https://python-all.ru/3.4/glossary.html#term-hashable) regardless of the referent; this avoids a number of problems related to their fundamentally mutable nature, and prevent their use as dictionary keys. *callback* is the same as the parameter of the same name to the [`ref()`](https://python-all.ru/3.4/library/weakref.html#weakref.ref) function.6970#### `weakref.getweakrefcount(object)`7172Возвращает количество слабых ссылок и прокси, которые ссылаются на *object*.7374#### `weakref.getweakrefs(object)`7576Возвращает список всех объектов слабых ссылок и прокси, которые ссылаются на *object*.7778#### `class weakref.WeakKeyDictionary([dict])`7980Класс отображения, который хранит слабые ссылки на ключи. Записи словаря будут удалены, когда на ключ больше не останется сильных ссылок. Это можно использовать для связывания дополнительных данных с объектом, принадлежащим другим частям приложения, без добавления атрибутов к этим объектам. Это особенно полезно для объектов, которые переопределяют доступ к атрибутам.8182> **Примечание**83>84> Предостережение: Поскольку [`WeakKeyDictionary`](https://python-all.ru/3.4/library/weakref.html#weakref.WeakKeyDictionary) построен на основе словаря Python, его размер не должен изменяться при итерации. Это может быть трудно обеспечить для [`WeakKeyDictionary`](https://python-all.ru/3.4/library/weakref.html#weakref.WeakKeyDictionary), потому что действия, выполняемые программой во время итерации, могут привести к тому, что элементы словаря исчезнут «магическим образом» (как побочный эффект сборки мусора).8586Объекты [`WeakKeyDictionary`](https://python-all.ru/3.4/library/weakref.html#weakref.WeakKeyDictionary) имеют следующие дополнительные методы. Они предоставляют прямой доступ к внутренним ссылкам. Ссылки не гарантированно являются «живыми» на момент их использования, поэтому результат вызова ссылок необходимо проверять перед использованием. Это можно использовать, чтобы избежать создания ссылок, которые заставят сборщик мусора хранить ключи дольше, чем необходимо.8788#### `WeakKeyDictionary.keyrefs()`8990Возвращает итератор по слабым ссылкам на ключи.9192#### `class weakref.WeakValueDictionary([dict])`9394Класс отображения, который хранит слабые ссылки на значения. Записи словаря будут удалены, когда на значение больше не будет сильных ссылок.9596> **Примечание**97>98> Предостережение: Поскольку [`WeakValueDictionary`](https://python-all.ru/3.4/library/weakref.html#weakref.WeakValueDictionary) построен на основе словаря Python, его размер не должен изменяться при итерации. Это может быть трудно обеспечить для [`WeakValueDictionary`](https://python-all.ru/3.4/library/weakref.html#weakref.WeakValueDictionary), потому что действия, выполняемые программой во время итерации, могут привести к тому, что элементы словаря исчезнут «магическим образом» (как побочный эффект сборки мусора).99100Объекты [`WeakValueDictionary`](https://python-all.ru/3.4/library/weakref.html#weakref.WeakValueDictionary) имеют следующие дополнительные методы. У этих методов такие же проблемы, как и у метода `keyrefs()` объектов [`WeakKeyDictionary`](https://python-all.ru/3.4/library/weakref.html#weakref.WeakKeyDictionary).101102#### `WeakValueDictionary.valuerefs()`103104Возвращает итератор по слабым ссылкам на значения.105106#### `class weakref.WeakSet([elements])`107108Класс множества, который хранит слабые ссылки на свои элементы. Элемент будет удален, когда на него больше не останется сильных ссылок.109110#### `class weakref.WeakMethod(method)`111112Пользовательский подкласс [`ref`](https://python-all.ru/3.4/library/weakref.html#weakref.ref), который имитирует слабую ссылку на привязанный метод (т.е. метод, определённый в классе и полученный через экземпляр). Поскольку привязанный метод эфемерен, стандартная слабая ссылка не может удерживать его. [`WeakMethod`](https://python-all.ru/3.4/library/weakref.html#weakref.WeakMethod) имеет специальный код для воссоздания привязанного метода до тех пор, пока не умрёт объект или исходная функция:113114```python115>>> class C:116...     def method(self):117...         print("method called!")118...119>>> c = C()120>>> r = weakref.ref(c.method)121>>> r()122>>> r = weakref.WeakMethod(c.method)123>>> r()124<bound method C.method of <__main__.C object at 0x7fc859830220>>125>>> r()()126method called!127>>> del c128>>> gc.collect()1290130>>> r()131>>>132```133134Новое в версии 3.4.135136#### `class weakref.finalize(obj, func, *args, **kwargs)`137138Возвращает вызываемый объект финализатора, который будет вызван, когда *obj* будет собран сборщиком мусора. В отличие от обычной слабой ссылки, финализатор всегда будет существовать до тех пор, пока не будет собран сам объект ссылки, что значительно упрощает управление жизненным циклом.139140Финализатор считается *живым*, пока он не вызван (явно или во время сборки мусора); после вызова он *мёртв*. Вызов живого финализатора возвращает результат вычисления `func(*arg, **kwargs)`, тогда как вызов мёртвого финализатора возвращает [`None`](https://python-all.ru/3.4/library/constants.html#None).141142Исключения, возникшие в колбэках финализатора во время сборки мусора, выводятся в стандартный поток ошибок, но не могут быть распространены. Они обрабатываются так же, как исключения, возникшие в методе [`__del__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__del__) объекта или в колбэке слабой ссылки.143144При завершении программы вызывается каждый оставшийся живой финализатор, если только его атрибут [`atexit`](https://python-all.ru/3.4/library/atexit.html#module-atexit) не установлен в false. Они вызываются в порядке, обратном порядку создания.145146Финализатор никогда не вызывает свой колбэк во время поздней фазы завершения интерпретатора, когда глобальные переменные модуля могут быть заменены на [`None`](https://python-all.ru/3.4/library/constants.html#None).147148#### `__call__()`149150Если *self* жив, то пометить его как мёртвый и вернуть результат вызова `func(*args, **kwargs)`. Если *self* мёртв, вернуть [`None`](https://python-all.ru/3.4/library/constants.html#None).151152#### `detach()`153154Если *self* жив, то пометить его как мёртвый и вернуть кортеж `(obj, func, args, kwargs)`. Если *self* мёртв, вернуть [`None`](https://python-all.ru/3.4/library/constants.html#None).155156#### `peek()`157158Если *self* жив, вернуть кортеж `(obj, func, args, kwargs)`. Если *self* мёртв, вернуть [`None`](https://python-all.ru/3.4/library/constants.html#None).159160#### `alive`161162Свойство, которое истинно, если финализатор жив, и ложно в противном случае.163164#### `atexit`165166Записываемое булево свойство, по умолчанию истинное. При завершении программы вызываются все оставшиеся живые финализаторы, для которых [`atexit`](https://python-all.ru/3.4/library/weakref.html#weakref.finalize.atexit) истинно. Они вызываются в порядке, обратном порядку создания.167168> **Примечание**169>170> Важно убедиться, что *func*, *args* и *kwargs* не содержат ссылок на *obj*, ни прямых, ни косвенных, иначе *obj* никогда не будет собран сборщиком мусора. В частности, *func* не должен быть привязанным методом *obj*.171172Новое в версии 3.4.173174#### `weakref.ReferenceType`175176Объект типа для объектов слабых ссылок.177178#### `weakref.ProxyType`179180Объект типа для прокси-объектов, которые не являются вызываемыми.181182#### `weakref.CallableProxyType`183184Объект типа для прокси вызываемых объектов.185186#### `weakref.ProxyTypes`187188Последовательность, содержащая все объекты типа для прокси. Это упрощает проверку, является ли объект прокси, без необходимости называть оба типа прокси.189190#### `exception weakref.ReferenceError`191192Исключение, возникающее при использовании прокси-объекта, когда исходный объект уже собран сборщиком мусора. Это то же самое, что и стандартное исключение [`ReferenceError`](https://python-all.ru/3.4/library/exceptions.html#ReferenceError).193194> **См. также**195>196> **[**PEP 0205**](https://python-all.ru/3.4/library/weakref.html) – Слабые ссылки**197>198> Предложение и обоснование этой возможности, включая ссылки на более ранние реализации и информацию о подобных возможностях в других языках.199200## 8.8.1. Объекты слабых ссылок201202Объекты слабых ссылок не имеют методов и атрибутов, кроме [`ref.__callback__`](https://python-all.ru/3.4/library/weakref.html#weakref.ref.__callback__). Объект слабой ссылки позволяет получить объект ссылки, если он ещё существует, вызвав его:203204```python205>>> import weakref206>>> class Object:207...     pass208...209>>> o = Object()210>>> r = weakref.ref(o)211>>> o2 = r()212>>> o is o2213True214```215216Если объект ссылки больше не существует, вызов объекта ссылки возвращает [`None`](https://python-all.ru/3.4/library/constants.html#None):217218```python219>>> del o, o2220>>> print(r())221None222```223224Проверять, жива ли ещё слабая ссылка, следует с помощью выражения `ref() is not None`. Обычно код приложения, которому нужно использовать объект ссылки, должен следовать такому шаблону:225226```python227# r – объект слабой ссылки228o = r()229if o is None:230    # объект был собран сборщиком мусора231    print("Object has been deallocated; can't frobnicate.")232else:233    print("Object is still live!")234    o.do_something_useful()235```236237Использование отдельной проверки «живучести» создаёт состояния гонки в многопоточных приложениях; другой поток может привести к инвалидации слабой ссылки до того, как она будет вызвана; идиома, показанная выше, безопасна как в многопоточных, так и в однопоточных приложениях.238239Специализированные версии объектов [`ref`](https://python-all.ru/3.4/library/weakref.html#weakref.ref) можно создавать с помощью наследования. Это используется в реализации [`WeakValueDictionary`](https://python-all.ru/3.4/library/weakref.html#weakref.WeakValueDictionary) для уменьшения накладных расходов памяти на каждую запись в отображении. Это может быть особенно полезно для связывания дополнительной информации со ссылкой, а также для добавления дополнительной обработки при вызовах получения объекта ссылки.240241В этом примере показано, как подкласс [`ref`](https://python-all.ru/3.4/library/weakref.html#weakref.ref) можно использовать для хранения дополнительной информации об объекте и изменения значения, возвращаемого при доступе к объекту ссылки:242243```python244import weakref245246class ExtendedRef(weakref.ref):247    def __init__(self, ob, callback=None, **annotations):248        super(ExtendedRef, self).__init__(ob, callback)249        self.__counter = 0250        for k, v in annotations.items():251            setattr(self, k, v)252253    def __call__(self):254        """Возвращает пару, содержащую объект и количество255        вызовов ссылки.256        """257        ob = super(ExtendedRef, self).__call__()258        if ob is not None:259            self.__counter += 1260            ob = (ob, self.__counter)261        return ob262```263264## 8.8.2. Пример265266Этот простой пример показывает, как приложение может использовать идентификаторы объектов для получения объектов, которые оно уже видело ранее. Идентификаторы объектов затем можно использовать в других структурах данных, не заставляя объекты оставаться живыми, но при этом объекты всё ещё можно получить по идентификатору, если они живы.267268```python269import weakref270271_id2obj_dict = weakref.WeakValueDictionary()272273def remember(obj):274    oid = id(obj)275    _id2obj_dict[oid] = obj276    return oid277278def id2obj(oid):279    return _id2obj_dict[oid]280```281282## 8.8.3. Объекты финализаторов283284Основное преимущество использования [`finalize`](https://python-all.ru/3.4/library/weakref.html#weakref.finalize) заключается в том, что он позволяет просто зарегистрировать колбэк без необходимости сохранять возвращаемый объект финализатора. Например285286```python287>>> import weakref288>>> class Object:289...     pass290...291>>> kenny = Object()292>>> weakref.finalize(kenny, print, "You killed Kenny!")  293<finalize object at ...; for 'Object' at ...>294>>> del kenny295You killed Kenny!296```297298Финализатор также можно вызывать напрямую. Однако финализатор вызовет колбэк не более одного раза.299300```python301>>> def callback(x, y, z):302...     print("CALLBACK")303...     return x + y + z304...305>>> obj = Object()306>>> f = weakref.finalize(obj, callback, 1, 2, z=3)307>>> assert f.alive308>>> assert f() == 6309CALLBACK310>>> assert not f.alive311>>> f()                     # колбэк не вызван, так как финализатор неактивен312>>> del obj                 # колбэк не вызван, так как финализатор неактивен313```314315Финализатор можно отменить с помощью его метода [`detach()`](https://python-all.ru/3.4/library/weakref.html#weakref.finalize.detach). Это уничтожает финализатор и возвращает аргументы, переданные конструктору при его создании.316317```python318>>> obj = Object()319>>> f = weakref.finalize(obj, callback, 1, 2, z=3)320>>> f.detach()                                           321(<__main__.Object object ...>, <function callback ...>, (1, 2), {'z': 3})322>>> newobj, func, args, kwargs = _323>>> assert not f.alive324>>> assert newobj is obj325>>> assert func(*args, **kwargs) == 6326CALLBACK327```328329Если не установить атрибут [`atexit`](https://python-all.ru/3.4/library/weakref.html#weakref.finalize.atexit) в [`False`](https://python-all.ru/3.4/library/constants.html#False), финализатор будет вызван при завершении программы, если он всё ещё жив. Например330331```python332>>> obj = Object()333>>> weakref.finalize(obj, print, "obj dead or exiting")  334<finalize object at ...; for 'Object' at ...>335>>> exit()                                               336obj dead or exiting337```338339## 8.8.4. Сравнение финализаторов с методами [`__del__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__del__)340341Предположим, мы хотим создать класс, экземпляры которого представляют временные каталоги. Каталоги должны удаляться вместе с их содержимым при наступлении первого из следующих событий:342343- объект удаляется сборщиком мусора,344- вызывается метод `remove()` объекта, или345- программа завершается.346347Можно попробовать реализовать класс с помощью метода [`__del__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__del__) следующим образом:348349```python350class TempDir:351    def __init__(self):352        self.name = tempfile.mkdtemp()353354    def remove(self):355        if self.name is not None:356            shutil.rmtree(self.name)357            self.name = None358359    @property360    def removed(self):361        return self.name is None362363    def __del__(self):364        self.remove()365```366367Начиная с Python 3.4, методы [`__del__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__del__) больше не препятствуют сборке мусора циклических ссылок, а глобальные переменные модулей больше не обнуляются до [`None`](https://python-all.ru/3.4/library/constants.html#None) во время завершения интерпретатора. Поэтому этот код должен без проблем работать в CPython.368369Однако обработка методов [`__del__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__del__), как известно, сильно зависит от реализации, поскольку опирается на внутренние детали реализации сборщика мусора интерпретатора.370371Более надёжная альтернатива – определить финализатор, который ссылается только на нужные ему функции и объекты, а не имеет доступ ко всему состоянию объекта:372373```python374class TempDir:375    def __init__(self):376        self.name = tempfile.mkdtemp()377        self._finalizer = weakref.finalize(self, shutil.rmtree, self.name)378379    def remove(self):380        self._finalizer()381382    @property383    def removed(self):384        return not self._finalizer.alive385```386387Определённый таким образом, наш финализатор получает только ссылку на те детали, которые нужны для корректной очистки каталога. Если объект никогда не будет удалён сборщиком мусора, финализатор всё равно будет вызван при завершении программы.388389Ещё одно преимущество финализаторов на основе weakref в том, что их можно использовать для регистрации финализаторов у классов, определение которых контролируется сторонними разработчиками, например, для выполнения кода при выгрузке модуля:390391```python392import weakref, sys393def unloading_module():394    # неявная ссылка на глобальные переменные модуля из тела функции395weakref.finalize(sys.modules[__name__], unloading_module)396```397398> **Примечание**399>400> Если создать объект финализатора в фоновом потоке прямо перед выходом из программы то есть вероятность, что финализатор не будет вызван при выходе. Однако в фоновом потоке [`atexit.register()`](https://python-all.ru/3.4/library/atexit.html#atexit.register), `try: ... finally: ...` и `with: ...` также не гарантируют, что очистка будет выполнена.401