Alla fine *credo* di aver trovato una soluzione *quasi* soddisfacente. Alcune scelte fanno cagare, ma per ora può andare. Condivido, per un ovvio atto di giustizia cosmica.
2015-03-08 15:12 GMT+00:00 Marco Giusti <marco.giu...@posteo.de>: > Il patter che più gli assomigli è l'Observer ma non sono sicuro che la > terminologia sia quella giusta in questo caso. Comunque > l'implementazione è all'incirca quella: > > ... > self._events = {} > > def register(self, event, callback): > self._events.setdefault(event, []).append(callback) > > def unregister(self, event, callback): > callbacks = self._events[event] > callbacks.pop(callbacks.index(callback)) > > def on_event(self, event, *args): > for callback in self._events[event]: > callback(*args) Questa implementazione va sicuramente bene per un meccanismo basilare, e le ho usate. Bene, Grazie Marco :) Però poi mi sono accorto che volevo qualcosa di più elaborato ed automatico. Fondamentalmente, quello che ho fatto è mettere in register() un sistema che, quando passo un oggetto, io registro in quell'oggetto una callback che - all'atto di distruzione - rimuove la callback originale. E questa callback che rimuove, viene schedulata per essere eseguita una volta sola, e poi rimossa automaticamente. Inoltre, per permettere di usare funzioni che incapsulassero i vari metodi, ho fatto in modo che register() prenda anche come parametro un oggetto da passare come primo argomento alla callback. In sostanza, il codice è questo: class Base: def register(self, event, target_obj, callback): if target_obj is None: def _call_once(*args, **kwargs): callback(*args, **kwargs) self.unregister(event, None, _call_once) self._callbacks.setdefault(event, []).append((None, _call_once)) else: self._callbacks.setdefault(event, []).append((target_obj, callback)) def _remove_cb(unused, obj): self.unregister(event, target_obj, callback) target_obj.register('on_remove', None, _remove_cb) def unregister(self, event, target_obj, callback): self._callbacks[event].remove((target_obj, callback)) def _run_callbacks(self, event, *args, **kwargs): for obj, cb in list(it for it in self._callbacks.get(event, [])): cb(obj, *args, **kwargs) def remove(self): self._run_callbacks('on_remove', self) Scelte di design: - passare l'oggetto (target_obj) esplicitamente in register() - schedulare una callback come "fire once" se target_obj è None. Avrei potuto usare un protocollo diverso, ma questo mi è sembrato un buon compromesso per ragioni che non sto a spiegare - lasciare che quando la callback è "fire once", le venga passato None come primo parametro. Solo per consistenza col resto - ogni callback registrata avrà una callback automatica di de-registrazione quando l'oggetto viene distrutto. Probabilmente è uno spreco di memoria e ci sono soluzioni migliori (tipo un metodo solo che rimuove tutte le callback associate all'oggetto, la lo lascio come esercizio al lettore :D). Punti interessanti: - in _run_callback costruisco una nuova lista perché può essere che cb chiami unregister() durante l'esecuzione. Probabilmente non è la soluzione migliore, comunque. - remove fa altre cose, ma è anche un esempio di come usare _run_callbacks. Non ho fatto dei gran test, ma per ora funzionicchia. Commenti ben accetti - ma considerate che è piuttosto legato al mio stile e alle necessità di questa applicazione, non l'ho pensato perché fosse generico. Ciauz ~Ale _______________________________________________ Python mailing list Python@lists.python.it http://lists.python.it/mailman/listinfo/python