Как хранить методы обратного вызова?

я пытаюсь сохранить некоторые обратные вызовы метода, но обращение к нему будет поддерживать связанный объект, поэтому я попытался сохранить метод weakref to, но это не кажется возможным?

so

  • Почему я не могу оставить слабого рефери? метод (см. пример ниже)

  • Как лучше всего сохранить ссылку на метод? что-нибудь в стандартной библиотеке? Или мне придется сохранить функцию и объект ref. отдельный?

пример:

import weakref

class A(object):
    def m(self): pass

a = A()

import weakref

class A(object):
    def m(self): pass

a = A()

rm = weakref.ref(a.m)
print "is weak ref to method dead?",rm() is None
print "Q1. why can't i keep weakref to bound method?"

ra = weakref.ref(a)
m = a.m
print "delete object"
del a
print "is object dead?",ra() is None
print "delete method"
del m
print "is object dead?",ra() is None
print "Q2. hmmm so i am stuck i can't keep a ref as it stops the object from gc, but weakref to method isn't working?"

person Anurag Uniyal    schedule 04.11.2009    source источник
comment
Что плохого в том, чтобы просто удалить объект из списка обратного вызова, чтобы удалить ссылку? Почему бы не написать метод отключения, который выполняет callback.remove(method)?   -  person S.Lott    schedule 04.11.2009
comment
да, это было бы здорово сделать, но все же, когда я сохраняю обратный вызов, я хотел бы, чтобы я мог слабо ссылаться на него, чтобы, если кто-то забудет отключиться, он автоматически отключился, не лучше ли автоматизировать отключение?   -  person Anurag Uniyal    schedule 04.11.2009
comment
Что не так с блоком with для обеспечения отключения?   -  person S.Lott    schedule 04.11.2009
comment
ничего плохого в «с», если его можно использовать во всех случаях, цель обратного вызова состоит в том, что когда-нибудь в будущем в каком-то событии будет вызван некоторый обратный вызов в каком-то объекте, как я могу вписаться в «с» здесь?   -  person Anurag Uniyal    schedule 04.11.2009


Ответы (4)


Я спросил t">тут же вопрос! В своем вопросе я говорю о GObject, но признаю, что это общая проблема для любого Python! Там мне помог lioro, и то, что я использую в своем текущем коде, показано ниже. Некоторые важные моменты:

  • Вы не можете ослабить ссылку на объект метода. Вы должны слабо указать экземпляр и его атрибут функции или просто имя метода (как я делаю в своем коде ниже)

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

.

class WeakCallback (object):
    """A Weak Callback object that will keep a reference to
    the connecting object with weakref semantics.

    This allows object A to pass a callback method to object S,
    without object S keeping A alive.
    """
    def __init__(self, mcallback):
        """Create a new Weak Callback calling the method @mcallback"""
        obj = mcallback.im_self
        attr = mcallback.im_func.__name__
        self.wref = weakref.ref(obj, self.object_deleted)
        self.callback_attr = attr
        self.token = None

    def __call__(self, *args, **kwargs):
        obj = self.wref()
        if obj:
            attr = getattr(obj, self.callback_attr)
            attr(*args, **kwargs)
        else:
            self.default_callback(*args, **kwargs)

    def default_callback(self, *args, **kwargs):
        """Called instead of callback when expired"""
        pass

    def object_deleted(self, wref):
        """Called when callback expires"""
        pass

Примечания по использованию:

# illustration how I typically use it
weak_call = WeakCallback(self._something_changed)
long_lived_object.connect("on_change", weak_call)

Я использую атрибут WeakCallback.token в подклассах, которые я сделал, чтобы управлять отключением обратного вызова, когда коннектор исчезает

person u0b34a0f6ae    schedule 04.11.2009
comment
у многих других есть указатель на подобное решение, но я выбрал это, потому что оно находится на странице - person Anurag Uniyal; 05.11.2009

Поскольку метод привязан к объекту, что вы ожидаете с ним делать, если объект не существует? Что содержало бы в себе?

Если вам не нужен объект в методе, сделайте его методом класса. Тогда ваш объект будет GC:d, даже если у вас есть обычная ссылка на метод.

person truppo    schedule 04.11.2009
comment
но в этом случае объект существует, в примере я не удаляю объект до конца - person Anurag Uniyal; 04.11.2009
comment
и я действительно хочу объект, мой простой вопрос заключается в том, есть ли способ сохранить обратные вызовы вокруг, как weakref для объектов, что-то в этом роде - person Anurag Uniyal; 04.11.2009

Рецепт 6.10 в Python Cookbook «Сохранение ссылок на связанные методы без запрета сборки мусора» предлагает довольно подробное, но краткое обсуждение и решения. Вы можете прочитать его в Интернете (в Google Книгах) здесь; мы отдаем должное этому рецепту Кнапке, Джоллитону и Никодимусу (частично из оригинального рецепта кулинарной книги активного состояния, о котором уже упоминался другой ответ), хотя, конечно, как обычно в Поваренной книге, мы (я, моя жена Анна и Дэвид Ашер) являемся отвечают за общий ход обсуждения и точную версию кода, выбранную для печати, поэтому, если с ними что-то не так, это наша вина;-).

person Alex Martelli    schedule 04.11.2009
comment
+1 за ваш ответ :), кстати, почему weakref.ref не работает для связанного метода? - person Anurag Uniyal; 04.11.2009
comment
@Anurag, он работает по назначению: он делает ссылку на связанный объект метода слабой! Таким образом, поскольку нет ссылки strong на этот связанный объект метода, указанный объект сразу становится недействительным - как и объясняется в обсуждении, на которое я уже указывал. - person Alex Martelli; 05.11.2009

У них есть хорошее решение в:

http://code.activestate.com/recipes/81253/

Взгляните на последний пример, опубликованный Anonymous.

person Bruno Oliveira    schedule 04.11.2009