Получить список слушателей черт характера, которые прислушиваются к моим чертам характера?

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

Спасибо!

Вот пример использования модуля Enthought Traits:

 from traits.api import  HasTraits,Str,Int,Float

 class GenerateEvents ( HasTraits ):
     name   = Str
     age    = Int
     weight = Float

 class ListenEvents ( HasTraits ):
     def _name_changed ( self, object, name, old, new ):
         print "_name_changed:", object, name, old, new

     def _age_changed ( self, object, name, old, new ):
         print "_age_changed:", object, name, old, new

     def _weight_changed ( self, object, name, old, new ):
         print "_weight_changed:", object, name, old, new

 class AnotherListenEvents ( HasTraits ):
     def _name_changed ( self, object, name, old, new ):
         print "Another _name_changed:", object, name, old, new

     def _age_changed ( self, object, name, old, new ):
         print "another _age_changed:", object, name, old, new

     def _weight_changed ( self, object, name, old, new ):
         print "another _weight_changed:", object, name, old, new

 ge = GenerateEvents()
 le = ListenEvents()
 ale = AnotherListenEvents()
 ge.set( name = 'Joe', age = 22, weight = 152.0 )
 ge.add_trait_listener( le )
 ge.add_trait_listener( ale )
 ge.set( name = 'Mike', age = 34, weight = 178.0 )

Обратите внимание, что ge имеет два слушателя, le и ale. Однако, учитывая ge, как я могу узнать, что это за слушатели? Обратите внимание, что слушатели могут динамически добавляться / удаляться в код, поэтому они не фиксируются.

Надеюсь, это немного проясняет.


person reckoner    schedule 10.12.2013    source источник
comment
Какую библиотеку вы используете? Покажите, пожалуйста, какой-нибудь образец или небольшой надуманный пример, демонстрирующий вашу проблему?   -  person James Mills    schedule 13.12.2013


Ответы (1)


Взгляните на ответ Роберта Керна в этой ветке из списка рассылки enthought-dev: http://engotit-dev.117412.n3.nabble.com/How-do-I-find-the-listeners-for-a-trait-td1716192.html

Вот модифицированная версия вашего кода с парой функций, добавленных для получения и отображения слушателей. Я добавил статический слушатель _age_changed, слушатель, созданный с помощью декоратора on_trait_change, и слушатель, созданный с помощью ge.on_trait_change(...).

from traits.api import (HasTraits, Str, Int, Float, on_trait_change,
                        TraitChangeNotifyWrapper)
from traits.trait_notifiers import StaticTraitChangeNotifyWrapper


def get_listeners(h):
    """
    h must be a HasTraits instance.

    Returns a dictionary whose keys are trait names and whose values
    are lists of notifiers.
    """
    listeners = {}
    for name in h.traits():
        notifiers = h.trait(name)._notifiers(0)
        if notifiers is not None:
            # Filter out the static listeners.  Comment this out
            # if you want to keep those.
            notifiers = [notifier for notifier in notifiers
                            if not isinstance(notifier, StaticTraitChangeNotifyWrapper)]
            listeners[name] = notifiers
    return listeners


def print_listeners(listeners):
    """
    Print the dictionary of listeners returned by `get_listeners(h)`.
    """
    for name, notifiers in listeners.items():
        print "trait '%s' has the following listeners:" % (name,)
        for notifier in notifiers:
            if notifier.name is None:
                handler = notifier.handler
                print "    '%s' %r" % (handler.__name__, type(handler))
            else:
                print "    '%s' on object %s" % (notifier.name, notifier.object)


class GenerateEvents ( HasTraits ):
    name   = Str
    age    = Int
    weight = Float

    def _age_changed(self, old):
        print "age changed from ", old, "to", self.age

    @on_trait_change('weight')
    def do_something(self, obj, name, old, new):
        print "do_something: name =", name


class ListenEvents ( HasTraits ):
    def _name_changed ( self, object, name, old, new ):
        print "_name_changed:", object, name, old, new

    def _age_changed ( self, object, name, old, new ):
        print "_age_changed:", object, name, old, new

    def _weight_changed ( self, object, name, old, new ):
        print "_weight_changed:", object, name, old, new


class AnotherListenEvents ( HasTraits ):
    def _name_changed ( self, object, name, old, new ):
        print "Another _name_changed:", object, name, old, new

    def _age_changed ( self, object, name, old, new ):
        print "another _age_changed:", object, name, old, new

    def _weight_changed ( self, object, name, old, new ):
        print "another _weight_changed:", object, name, old, new


def printit(foo):
    print foo


ge = GenerateEvents()
le = ListenEvents()
ale = AnotherListenEvents()
ge.set( name = 'Joe', age = 22, weight = 152.0 )
ge.add_trait_listener( le )
ge.add_trait_listener( ale )
ge.set( name = 'Mike', age = 34, weight = 178.0 )

# Make the function `printit` a listener to ge.name.
ge.on_trait_change(printit, name='name')

Вот что вы получите, запустив его (в ipython):

In [103]: run trait_listeners_question
age changed from  22 to 22
do_something: name = weight
age changed from  34 to 34
_age_changed: <__main__.GenerateEvents object at 0x2680950> age 22 34
another _age_changed: <__main__.GenerateEvents object at 0x2680950> age 22 34
_name_changed: <__main__.GenerateEvents object at 0x2680950> name Joe Mike
Another _name_changed: <__main__.GenerateEvents object at 0x2680950> name Joe Mike
do_something: name = weight
_weight_changed: <__main__.GenerateEvents object at 0x2680950> weight 152.0 178.0
another _weight_changed: <__main__.GenerateEvents object at 0x2680950> weight 152.0 178.0

In [104]: listeners = get_listeners(ge)

In [105]: print_listeners(listeners)
trait 'trait_added' has the following listeners:
    '_trait_added_changed' on object <weakref at 0x2656d08; to 'ListenEvents' at 0x2680d70>
    '_trait_added_changed' on object <weakref at 0x2656e68; to 'AnotherListenEvents' at 0x26808f0>
trait 'age' has the following listeners:
    '_age_changed' on object <weakref at 0x2656c58; to 'ListenEvents' at 0x2680d70>
    '_age_changed' on object <weakref at 0x2656db8; to 'AnotherListenEvents' at 0x26808f0>
trait 'ev' has the following listeners:
    '_ev_changed' on object <weakref at 0x2656c00; to 'ListenEvents' at 0x2680d70>
trait 'name' has the following listeners:
    '_name_changed' on object <weakref at 0x2656cb0; to 'ListenEvents' at 0x2680d70>
    '_name_changed' on object <weakref at 0x2656e10; to 'AnotherListenEvents' at 0x26808f0>
    'printit' <type 'function'>
trait 'weight' has the following listeners:
    'do_something' on object <weakref at 0x2671368; to 'GenerateEvents' at 0x2680950>
    '_weight_changed' on object <weakref at 0x2656ba8; to 'ListenEvents' at 0x2680d70>
    '_weight_changed' on object <weakref at 0x2656d60; to 'AnotherListenEvents' at 0x26808f0>
person Warren Weckesser    schedule 16.12.2013
comment
Это не работает, если я и свойство Event ev присваивают объекту ge соответствующий ev_changed или ev_fired обработчик для le. Разве это невозможно с использованием этой техники? - person reckoner; 16.12.2013
comment
Я обновил код, поэтому он также возвращает Event признаков. Имейте в виду, что эта версия также включает автоматически добавленную черту trait_added Event. (Другой автоматически добавляемый признак - trait_modified, но в этом случае его вызов _notifiers(0) возвращает None.) - person Warren Weckesser; 16.12.2013