Three implementations of observable objects I wonder, what might be the best (most pythonic) way of implementing multiple observerables in Python.  There are multiple objects, which should be able to register themselves at one or multiple observables.

Shall I simply submit the update methods, like this:

class MethodObservable():
    def __init__(self, data_source):
        self.observers = []
        self.data_source = data_source

    def add(self, callback):
        self.observers.add(callback)

    def remove(self, callback):
        try:
            self.observers.remove(callback)
        except ValueError:
            pass

    def notify():
        for callback in self.observers:
            callback(self.data_source)

class MethodObserver():
    def __init__(self, observer1, observer2):
        observer1.add(self.update_for_1)
        observer2.add(self.update_for_2)

    def update_for_1(self, data_source):
        # code

    def update_for_2(self, data_source):
        # code

data_source1 = SomeObject()
data_source2 = SomeOtherObject()
observable1 = MethodObservable(data_source1)
observable2 = MethodObservable(data_source2)
observer = MethodObserver(observable1, observable2)


Or is it better, to come up with a dictionary of classes and methods:

class DictObservable():
    def __init__(self, data_source):
        self.observers = {}
        self.data_source = data_source

    def add(self, observer, callback):
        self.observers[observer] = callback

    def remove(self, observer):
        try:
            del self.observers[observer]
        except ValueError:
            pass

    def notify():
        for callback in self.observers.values():
            callback(self.data_source)

class DictObserver():
    def __init__(self, observer1, observer2):
        observer1.add(self, self.update_for_1)
        observer2.add(self, self.update_for_2)

    def update_for_1(self, data_source):
        # code

    def update_for_2(self, data_source):
        # code

data_source1 = SomeObject()
data_source2 = SomeOtherObject()
observable1 = DictObservable(data_source1)
observable2 = DictObservable(data_source2)
observer = DictObserver(observable1, observable2)


Or is probably the best way, that a class, which registers to a specific observer should have a specified update/callback-method, which kind of enforces the implementation of an interface:

class SpecifiedObservable():
    def __init__(self, data_source, callback_method='update'):
        self.observers = []
        self.data_source = data_source
        self.callback_method = callback_method

    def add(self, observer):
        self.observers.add(observer)

    def remove(self, observer):
        try:
            self.observers.remove(observer)
        except ValueError:
            pass

    def notify():
        for observer in self.observers:
            getattr(observer, self.callback_method)(self.data_source)

class SpecifiedObserver():
    def __init__(self, observer1, observer2):
        observer1.add(self)
        observer2.add(self)

    def update_for_1_specified(self, data_source):
        # code

    def update(self, data_source):
        # code

data_source1 = SomeObject()
data_source2 = SomeOtherObject()
observable1 = SpecifiedObservable(data_source1, 'update_for_1_specified')
observable2 = SpecifiedObservable(data_source2)
observer = SpecifiedObserver(observable1, observable2)


Maybe there are even better options, I wonder, which one should be preferred?
First thing, you should use new-style classes, inheriting from object. (Not necessary if you are in Python3, but convenient for backwards compatibility).

So, in short, your choices are:


Store them in a list
Store them in a dictionary


Of the two, the dictionary is the best option, because the keys are stored in a hash table, and you can look up items in O(1), whereas in the list you have to transverse the whole thing until you find it, so it is O(N).

Now, note that your dictionary implementation is a very thin layer on top of a dict. I would recommend inheriting from dict. If you are bound to the specific interface (.add, .remove) instead of the __setitem__ and pop, you can just create aliases. This can help you reduce the amount of code and also give you easier access to all the expresiveness of Python dicts.

Note that the third method is broken. In particular:

self.observers.add(observer)


when self.observers is a list, that doesn't have the method add.