Когда использовать слабые ссылки в Python?

может ли кто-нибудь объяснить использование слабых ссылок?

на документация не объясняет это точно, он просто говорит, что GC может уничтожить объект, связанный с помощью слабой ссылки в любое время. Тогда какой смысл иметь объект, который может исчезнуть в любой момент? Что если мне нужно использовать его сразу после того, как он исчез?

не могли бы вы объяснить их хорошими примерами?

спасибо

3 ответов


типичное использование для слабых ссылок-если A имеет ссылку на B и B имеет ссылку на A. без надлежащего сборщика мусора, обнаруживающего цикл, эти два объекта никогда не получат GC'D, Даже если нет ссылок ни на один из "снаружи". Однако, если одна из ссылок "слабая", объекты будут правильно GC'D.

Однако, Python тут имейте цикл-обнаруживая сборщик отброса (с 2.0!), так что это не считается:)

другое применение для слабых ссылок - для кэшей. Это упоминается в weakref документы:

основное использование для слабых ссылок-реализация кэшей или сопоставлений, содержащих большие объекты, где желательно, чтобы большой объект не поддерживался только потому, что он появляется в кэше или сопоставлении.

Если GC решает уничтожить один из этих объектов, и вам это нужно, вы можете просто пересчитать / восстановить данные.


события являются общим сценарием для слабых ссылок.


обратите внимание, что мне пришлось поставить gc.collect() здесь, чтобы убедиться, что приемник действительно очищен немедленно. Это необходимо здесь, потому что теперь есть цикл сильных ссылок: связанный метод относится к получателю и наоборот.

это не очень плохо; это означает только, что очистка приемника будет отложена до следующего запуска сборщика мусора. Циклические ссылки не могут быть очищены простым механизмом подсчета ссылок.

если вы действительно хотите, вы можете удалить сильный ссылочный цикл, заменив связанный метод пользовательским объектом функции, который сохранит его self как слабая ссылка тоже.

def __init__(self, emitter):

    # Create the bound method object
    weakself = weakref.ref(self)
    def cb(msg):
        self = weakself()
        self.callback(msg)

    # Register it
    emitter.listeners.add(cb)
    # But also create an own strong reference to keep it alive
    self._callbacks = set([cb])

давайте поместим эту логику в вспомогательную функцию:

def weak_bind(instancemethod):

    weakref_self = weakref.ref(instancemethod.im_self)
    func = instancemethod.im_func

    def callback(*args, **kwargs):
        self = weakref_self()
        bound = func.__get__(self)
        return bound(*args, **kwargs)

    return callback

class Receiver(object):

    def __init__(self, emitter):

        cb = weak_bind(self.callback)

        # Register it
        emitter.listeners.add(cb)
        # But also create an own strong reference to keep it alive
        self._callbacks = set([cb])

теперь нет цикла сильных ссылок, так что, когда Receiver освобождается, функция обратного вызова также будет освобождена (и удалена из WeakSet) немедленно, без необходимости полного цикла GC.


 - Weak references is an important concept in python, which is missing
   in languages likes Java(java 1.5).
 - In Observer design pattern, generally Observable Object must maintain
   weak references to the Observer object.

   eg. A emits an event done() and B registers with A that, it want to
   listen to event done(). Thus, whenever done() is emitted, B is
   notified. But If B isn't required in application, then A must not
   become an hinderance in the garbage collection in A(since A hold the
   reference to B). Thus, if A has hold weak reference to B, and when
   all the references to A are away, then B will be garbage collected.
 - It's also very useful in implementing caches.