###################################################################### ## ## Events ## ###################################################################### class Events: def __getattr__(self, name): if hasattr(self.__class__, '__events__'): assert name in self.__class__.__events__, \ "Event '%s' is not declared" % name self.__dict__[name] = ev = _EventSlot(name) return ev def __repr__(self): return 'Events' + str(list(self)) __str__ = __repr__ def __len__(self): return NotImplemented def __iter__(self): def gen(dictitems=self.__dict__.items()): for attr, val in dictitems: if isinstance(val, _EventSlot): yield val return gen() class _EventSlot: def __init__(self, name): self.targets = [] self.__name__ = name def __repr__(self): return 'event ' + self.__name__ def __call__(self, *a, **kw): for f in self.targets: f(*a, **kw) def __iadd__(self, f): self.targets.append(f) return self def __isub__(self, f): while f in self.targets: self.targets.remove(f) return self ###################################################################### ## ## Demo ## ###################################################################### if __name__ == '__main__': class MyEvents(Events): __events__ = ('OnChange', ) class ValueModel(object): def __init__(self): self.events = MyEvents() self.__value = None def __set(self, value): if (self.__value == value): return self.__value = value self.events.OnChange() ##self.events.OnChange2() # would fail def __get(self): return self.__value Value = property(__get, __set, None, 'The actual value') class SillyView(object): def __init__(self, model): self.model = model model.events.OnChange += self.DisplayValue ##model.events.OnChange2 += self.DisplayValue # would raise exeception def DisplayValue(self): print self.model.Value model = ValueModel() view = SillyView(model) print '\n--- Events Demo ---' # Events in action for i in range(5): model.Value = 2*i + 1 # Events introspection print model.events for event in model.events: print event