Re: [Python] Gestire eventi con callback
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 : > 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
Re: [Python] Smettete di scrivere shell script (era: Re: Lanciare script da altro script)
2015-03-06 17:08 GMT+00:00 Enrico Bianchi : > On Wednesday, March 04, 2015 07:39:20 AM enrico franchi wrote: > > > Se vuoi usare Python per fare automazione di cose, ti troverai spesso ad > > usare subprocess. Mica per altro... semplicemente molti task specifici > non > > hanno un equivalente di libreria (e scriverlo costa troppo), > > E` per questi casi che dico che subprocess dev'essere usato solo se > strettamente necessario > Senti, davvero... io non riesco a seguire i tuoi flussi di pensiero. Questo thread, e' nato da OP che parlava appunto di come fare a scriptare il fatto che doveva lanciare quattro programmi. Da cui il mio suggerimento di usare bash. E il fatto che, per una cosa cosi' semplice, trovo farlo in Python con subprocess piu' scomodo che farlo in bash. Questo giusto per dare contesto. Per il resto, nessuno dice che devi usare subprocess a sproposito o simili. Io mi limito a dire che usare subprocess "al posto di bash" non e' comodo. O meglio, io non lo trovo comodo. Tutto il resto sono discussioni su casi specifici che non hanno senso senza vedere i casi specifici stessi. > > > Tra l'altro, sei d'accordo con me che si, bash puo' avere senso. Giuro > che > > non capisco quale sia il punto. > > Il punto e` che scelgo di usare Python lo faccio perche` posso usare la sua > libreria, e non comandi shell, che mi viene comoda in una serie smodata di > contesti > Dai, rileggiti il thread, davvero. Io credo che siamo in quasi completo accordo su tutta la faccenda. Non e' che con tutti questi interventi pensavi di rispondere a qualcun altro? Cioe' la mia tesi e' che per chiamare quattro comandi shell in croce sia da valutare il fatto che usare bash puo' essere piu' comodo farlo in bash che usando subprocess. Non stiamo parlando di complessi controlli di flusso, di librerie, di niente. -- . ..: -enrico- ___ Python mailing list Python@lists.python.it http://lists.python.it/mailman/listinfo/python
Re: [Python] Gestire eventi con callback
2015-03-08 21:31 GMT+01:00 Alessandro Re : > 2015-03-08 20:24 GMT+00:00 Manlio Perillo : > > Intendevo dire cosa usi per chiamare il codice C++. > > Ah, forse ho capito: intendi dire se uso qualche modulo python per > usare C++, tipo ctypes? > Non uso niente di simile: sto usando una libreria che ha dei binding > in python, quindi includo il modulo, eredito una classe e costruisco > su quella. > > L'unica soluzione "semplice" che mi venga in mente, è quella di costruire dei proxy alle instanze delle classi C++ che usi, così come il modulo weakref lo fa per oggetti Python. Che io sappia in C++ l'unico modo per creare un proxy per una classe CT è quello di creare una sotto classe e ridefinire i costruttori e il distruttore. class PT public CT { // nel costruttore accetti una callback // nel distruttore chiami la callback } Quindi quando il codice originale richiede un CT, tu instanzi e passi un PT. Temo però che per casi non banali sia un bagno di sangue farlo a mano. Però se la cosa è fattibile, sicuramente qualcuno l'ha già implementata Ciao Manlio ___ Python mailing list Python@lists.python.it http://lists.python.it/mailman/listinfo/python
Re: [Python] Lanciare script da altro script
2015-03-06 17:23 GMT+00:00 Enrico Bianchi : > On Tuesday, March 03, 2015 03:28:15 PM enrico franchi wrote: > > (reinvio per scazzi con client email) > > 3. e' qualcosa che fa "solo" I/O bound; per il CPU bound devi sempre >> andare >> vecchia maniera. multiprocessing o incrociare le dita con i thread. >> > > https://docs.python.org/3/library/concurrent.futures.html ? > > Si, leggila la pagina che linki pero'... :) Quella e' una API costruita su... multiprocessing oppure threading. In altre parole, siamo punto a capo. -- . ..: -enrico- ___ Python mailing list Python@lists.python.it http://lists.python.it/mailman/listinfo/python