george young <gry at ll.mit.edu> writes:
> I'm using an observer pattern as part of a model-view-presenter/controller GUI
> app. I had simply grabbed someone's source file with observer/observable
> classes and crunched along, inheriting from these classes and using register,
> notify, etc. But it seems to me that the classic Observable (adapted from
> type-anal C++):
>> class Observable:
> def __init__(self):
> self.observers = []
> def register(self, o):
> self.observers.append(o)
> def un_register(self, o):
> self.observers.remove(o)
> def notify(self):
> for o in self.observers:
> o.update(self)
>> class Myobservable(Observable):
> whatever...
>> class Myobserver:
> def update(selfm model):
> self.crunchnewvalue(model.get())
> def __init__(self):
> mo = myobservable()
> mo.register(self)
>> is unnecessarily restrictive and inflexible for python code.
> Why require an observer to
> observable.register(self)
> and define a member update(self), when it seems like the observable
> could just take a callable object and call it:
>> class NewObservable:
> ....
> def notify(self):
> for o in self.observers:
> o()
>> ob = myobserverclass()
> ob.register(ob.somefunc)
>> This scheme keeps the simplest interface, but allows one observer to
> have as many different observables as wanted, with different update
> functions. Or one update func with different attributes via a lamda curry:
>> ob1.register(lambda :ob.func(someval))
> ob2.register(lambda :ob.func(otherval))
>> Am I missing something? Am I still suffering from C++ toxicity after
> two years of pythonic bliss?
The only thing that you might be missing is that you are not going far
enough. Rather than requiring lambdas to pass arguments, harness even
more of Python's dynamic nature and use this:
class NewObservable:
def __init__(self):
self.observers = []
def register(self, func, *args, **kw):
self.observers.append((func, args, kw))
def notify(self):
for func, args, kw in self.observers:
func(*args, **kw)
# meanwhile, in a class on the other side of town:
ob1.register(self.method, someval)
ob2.register(self.method, otherval)
Working out how to write un_register is left as an excercise for the
reader.
--
Tim Evans