[Python] Gestire eventi con callback
Marco Giusti
marco.giusti a posteo.de
Dom 8 Mar 2015 08:54:10 CET
On Sun, Mar 08 2015, Alessandro Re wrote:
> Ciao lista,
>
> ho un problema con delle callback, e sapendo che ci sono sistemi in
> cui si usano molto (e.g. in ambito web), magari qualcuno di voi mi può
> illuminare (scusate, il post è un po' lungo).
>
> Ho degli oggetti python che fanno riferimento a degli oggetti C++,
> quindi a volte mi trovo nella situazione in cui un oggetto C++ viene
> distrutto e, se l'oggetto python esiste ancora e cerca di far
> riferimento ad esso, provoca - giustamente - errore.
>
> Ora, dal lato python ho delle callback per gestire degli eventi che
> arrivano da C++: quando un certo evento accade, una funzione python
> viene chiamata.
>
> Quindi immaginate di avere un oggetto A che emette un evento E, ed un
> oggetto B che ha una callback C associata ad E: quando E accade, C
> viene chiamata.
>
> Il problema è questo: può capitare che un metodo remove() di B venga
> chiamato, provocando la rimozione dell'oggetto C++ sottostante; ma non
> dell'oggetto python B, perché la sua callback è ancora registrata. Se
> per caso in C venisse usato l'oggetto C++, si alzerebbe una bella
> eccezione.
>
> Ora, la mia domanda è: come posso costruire in python un sistema in
> cui io posso attaccare due oggetti, ma quando un certo metodo (e.g.
> remove) viene chiamato, allora tutte le callback registrate vengono
> rimosse senza troppo sforzo e tutti gli oggetti garbage-collected come
> ci si aspetterebbe?
C == oggetto in c++ con riferimento all'oggetto python
P == oggetto python
Come registri le callback? Gli oggetti in python sono referenziati da
del codice python o solo dalle callback di c++? In questo caso basta
che, nel momento in cui distruggi l'oggetto C, deregistri le callback
e riduci il numero di referenze del metodo. Se i metodi di un oggetto
P sono usati come callback di un solo oggetto C, al momento che
tu rilasci tutte le callback non esistono più riferimenti all'oggetto
python.
Se al momento della distruzione dell'oggetto C vuoi chiamare un'ultima
callback, chiama la callback e poi rimuovi il riferimento alla stessa.
> Conoscete dei pattern, degli idiomi, o qualunque cosa per poter
> implementare questo?
>
> Ho poi una seconda domanda, che fortunatamente richiede meno parole :)
>
> A volte, viene dato un certo comando, ad esempio "send_data(123)";
> questa operazione viene fatta in modo asincrono, cioé il controllo
> torna subito all'utente e una callback verrà chiamata quando
> l'operazione è stata completata.
>
> Come posso rendere sincrona (bloccante) l'invocazione di un comando?
>
> Un modo tanto semplice quanto barbaro è il seguente:
>
> free_to_go = False
> def on_packet_sent():
> global free_to_go
> free_to_go = True
>
> def send_data_blocking(data):
> global free_to_go
> free_to_go = False
> send_data(data, callback=on_packet_sent)
> while not free_to_go:
> pass
>
> send_data_blocking(123)
La prima idea che mi viene in mente è di infilare la callback dentro la
send e di chiamare sleep per salvare qualche ciclo macchina:
def send_data_blocking(data):
def go():
free_to_go = True
free_to_go = False
send_data(data, callback=go)
while not free_to_go:
sleep(0.1)
abbastanza naïve ma non dai tante informazioni a proposito e quindi per
esempio nessuna gestione degli errori. send_data a parte il codice è
thread-safe.
ciao
m.
Maggiori informazioni sulla lista
Python