Topic: [RISOLTO] Tenere il conto delle istanze di uno script  (Letto 199 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline marcus72

  • python unicellularis
  • *
  • Post: 32
  • Punti reputazione: 0
    • Mostra profilo
[RISOLTO] Tenere il conto delle istanze di uno script
« il: Dicembre 28, 2018, 17:24 »
Salve a tutti.
Avendo fatto uno script con interfaccia grafica tkinter, ho la necessità di sapere se viene eseguito più volte contemporaneamente (per gestire un file di status in cui vengono salvati alcuni parametri quali ad esempio posizione e dimensioni, necessariamente diversi per ogni istanza), e quindi sapere se è il primo a partire o il secondo, ecc.
L'unica strada percorribile penso sia con un socket. Ma così dovrei far partire un processo figlio che fa da server e che tenga il conto... Quindi la prima istanza fa partire questo server, che quindi parte il conto da 1. La seconda istanza fa da client, così che il server possa dirgli che il prossimo numero di istanza disponibile è 2. La terza istanza, allo stesso modo, interroga il server, che gli risponderà con 3. E così via.
Ma mi vengono in mente 2 problemi:
1) Se si chiude la prima istanza, questa chiuderà forzatamente anche il server, e quindi salta tutto.
2) Dover lasciare un server in attesa mi fa sospettare una pesantezza eccessiva per il sistema, magari evitabile.
Chiedo quindi se c'è un modo migliore per risolvere il problema.
Grazie.
« Ultima modifica: Dicembre 30, 2018, 23:25 da marcus72 »

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 2.851
  • Punti reputazione: 9
    • Mostra profilo
Re:Tenere il conto delle istanze di uno script
« Risposta #1 il: Dicembre 28, 2018, 18:05 »
uhm, non è che sia molto chiaro. Dici che potresti avere diverse istanze in esecuzione contemporaneamente *sulla stessa macchina*? Di un *programma gui*? Mah, questo mi sembra davvero insolito, ma poco male.
A me sembra che la cosa più semplice potrebbe essere che ogni istanza, appena viene avviata, preleva il clock del sistema e lo conserva in una variabile globale. Ogni volta che l'istanza deve scrivere sul tuo "file di status" firma il suo record con quel clock. Questo dovrebbe bastare a identificare univocamente ciascuna istanza. Inoltre, a un clock più grande corrisponde un'istanza avviata dopo.
Semmai, mi sembra assai più problematica la tua decisione di usare un file come collettore di scritture concorrenti. A quel punto sei in balia dei capricci del sistema operativo. Magari ti andrà sempre bene (anzi, quasi certamente ti andrà sempre bene se davvero si tratta di più istanze di programmi gui su una stessa macchina... dopo tutto non è che l'utente possa cliccare alla velocità della luce). In generale, sarebbe meglio usare un database per queste cose (magari anche solo file-based come sqlite, ma almeno a quel punto sai che ci pensa lui a gestire i lock del sistema operativo). E se usi un database, allora ovviamente tutti i tuoi problemi spariscono di colpo. Basta che ogni istanza, all'avvio, si registri presso il database, ottenendo in cambio un "ticket" (un semplice intero progressivo, se vuoi) che la identifica univocamente.

Offline marcus72

  • python unicellularis
  • *
  • Post: 32
  • Punti reputazione: 0
    • Mostra profilo
Re:Tenere il conto delle istanze di uno script
« Risposta #2 il: Dicembre 28, 2018, 18:56 »
uhm, non è che sia molto chiaro. Dici che potresti avere diverse istanze in esecuzione contemporaneamente *sulla stessa macchina*? Di un *programma gui*? Mah, questo mi sembra davvero insolito, ma poco male.

Sì, esattamente: sulla stessa macchina si può aprire questo programma anche 2 o 3 volte contemporaneamente. Può capitare con la calcolatrice, per esempio... anche VLC lo prevede (per mixare musica)... Mi è capitato, usando il mio programma in ufficio, di aprirlo due volte (non so se ti è mai capitato che mentre stai facendo un lavoro, ti interrompano per farne un altro più urgente, e magari ti re-interrompono per farne un'altro, ancora più urgente... Purtroppo a me capita.)

A me sembra che la cosa più semplice potrebbe essere che ogni istanza, appena viene avviata, preleva il clock del sistema e lo conserva in una variabile globale. Ogni volta che l'istanza deve scrivere sul tuo "file di status" firma il suo record con quel clock. Questo dovrebbe bastare a identificare univocamente ciascuna istanza. Inoltre, a un clock più grande corrisponde un'istanza avviata dopo.
Semmai, mi sembra assai più problematica la tua decisione di usare un file come collettore di scritture concorrenti.
Guarda, la cosa che mi serve è estremamente più semplice: il mio programma, appena aperto legge lo stato precedente (un file di testo nel quale c'è la posizione della finestra sullo schermo, la sua dimensione e poche altre impostazioni), così all'apertura si trova esattamente come nell'ultima chiusura. Quando poi viene chiuso, controlla se lo stato è cambiato, e se lo è aggiorna il file relativo. Stop. Non ho messo in conto nessuna scrittura concorrente... Allo stato attuale delle cose, la seconda finestra mi si apre esattamente sulla prima, il che è una scocciatura doverla spostare. Poi, ovviamente, lo stato salvato coincide con lo stato dell'ultima finestra chiusa. Quindi non si prevede (e nel mio caso non avrebbe senso) la memorizzazione di vari stati, per cui l'uso di un db mi pare eccessivo. Tra l'altro, a quel punto, avrei il problema di sapere qual è l'ultimo stato da ripristinare (nel senso che avrei ugualmente il problema di sapere se l'istanza appena partita è la 1^ o la 2^). La mia idea invece era, per esempio: apro il mio programma e si posiziona, per esempio, nell'angolo in alto a destra; lo apro di nuovo, e si posiziona nell'angolo in basso a destra. E per fare questo immaginavo bastasse memorizzare un file "stato1", per esempio, ed uno "stato2" (che chiaramente si genera da solo se il programma capisce che è la 2^ istanza). Quindi quello che speravo di poter ottenere è una funzione che mi dica se il programma lo sto aprendo per la prima volta, o è la seconda o la terza volta.

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 2.851
  • Punti reputazione: 9
    • Mostra profilo
Re:Tenere il conto delle istanze di uno script
« Risposta #3 il: Dicembre 28, 2018, 22:28 »
Citazione
Sì, esattamente: sulla stessa macchina si può aprire questo programma anche 2 o 3 volte contemporaneamente. Può capitare con la calcolatrice, per esempio... anche VLC lo prevede (per mixare musica)...
Ah sì, ma quando è così in genere si suppone che le diverse istanze facciano qualcosa di completamente scorrelato e non abbiano bisogno di conservare uno stato comune... tu invece vuoi avere uno stato in comune (che poi tu "lo usi tanto" o "lo usi poco", non importa).

(Detto questo, c'è sicuramente qualcosa di interessante, qui. Da una rapida prova, se avvio diverse istanze di calc.exe Windows "se ne accorge" e le apre in posizioni diverse. Se invece ci provo con notepad.exe, Windows le apre sempre esattamente nello stesso posto. Uhm... boh? Direi che almeno a livello di sistema operativo dev'essere possibile una cosa simile a quella che vuoi fare tu, ma onestamente non saprei... dovrei cercare)

Citazione
Mi è capitato, usando il mio programma in ufficio, di aprirlo due volte (non so se ti è mai capitato che mentre stai facendo un lavoro, ti interrompano per farne un altro più urgente, e magari ti re-interrompono per farne un'altro, ancora più urgente... Purtroppo a me capita.)
Sì ma capisci, questo è un hack da utente smaliziato, non è una feature del programma. In genere uno scenario simile capita di rado, e i progammi non lo supportano. Una istanza del programma deve essere responsabile di se stessa (e se vuole persistere il suo stato, lo farà per conto suo), non deve mettersi ad "annusare in giro" se ci sono altre istanze contemporaneamente in esecuzione. Se l'utente decide di aprire più istanze, sono fatti suoi e se le gestirà lui, nel quadro di quello che il sistema operativo gli consente di fare.
Di conseguenza, se ritieni di dover supportare lo scenario "più versioni in esecuzione" (e non sto dicendo che sarebbe una buona idea... anzi), allora forse ti consiglio di supportarlo "da dentro il programma", non "da fuori". Ovvero, una sola istanza del programma che consente di aprire molteplici istanze della finestra, per esempio. Un po' come puoi aprire diversi documenti in un programma di videoscrittura.

Citazione
il mio programma, appena aperto legge lo stato precedente (un file di testo nel quale c'è la posizione della finestra sullo schermo, la sua dimensione e poche altre impostazioni), così all'apertura si trova esattamente come nell'ultima chiusura. Quando poi viene chiuso, controlla se lo stato è cambiato, e se lo è aggiorna il file relativo. Stop.
Ecco, questo (e solo questo!) è molto chiaro, e si chiama "persistere lo stato del programma". Puoi usare file di configurazione, database, pickle dump... quello che ti pare. Puoi persistere la posizione della finestra, l'ultimo documento aperto, le preferenze dell'utente... quello che vuoi. Fin qui è tutto molto chiaro ed è un pattern molto comune.
Il problema è che dopo aver scritto "Stop", tu invece non ti stoppi per niente e vai avanti a descrivere una situazione che è quasi sicuramente incompatibile con questa cosa semplice e comune che hai appena scritto. Ora, io non so di *quali* impostazioni tu stai parlando (dici "poche altre impostazioni", ma capisci... non è molto d'aiuto). Però pensaci nel caso generico:
- Apri l'istanza "A": questa registra in un file il suo status, e scrive "sono A e sono fatta così e così".
- Poi apri l'istanza "B", e questa fa la stessa cosa: "sono B, bla bla bla". Ovviamente fai anche tutto il tuo giro di danza che ti piace, per cui se B scopre che c'è già A aperta allora non va a mettersi proprio sopra A, etc. etc.
- Poi chiudi A, e A registra nel file di status che si è chiusa.
- Poi chiudi B, stessa cosa.
Adesso, quando vuoi aprire una nuova istanza... che cosa vuoi fare davvero? Aprire di nuovo A, aprire di nuovo B, oppure aprire qualcosa di vergine? Ovviamente puoi inventarti delle regole... anche molto strane e sofisticate... per esempio, se non c'è nessuna istanza già aperta allora vuoi aprire A, se A è già aperta allora apri una B, e se A e B sono entrambe già aperte, allora apri una nuova istanza vergine e la chiami C. Ma dopo un po', che cosa succede se l'utente vuole sbarazzarsi per sempre di B, e non vuole mai più aprirla? Boh. Eccetera eccetera.
Insomma, "persistere lo stato del programma" quando possono esserci più istanze del programma, è un po' un casino. Non importa che siano "solo poche impostazioni". Ti invito a rifletterci sopra a fondo.

Tuttavia, *se* quello che vuoi è davvero solo e semplicemente:
- che se c'è un'altra istanza aperta, allora quella nuova si sposta un po' più in là...
(ma nota bene: questo *NON* è affatto quello che hai detto)
Beh, allora mi sembra francamente una complicazione inutile per il tuo programma, per una feature che tanto all'utente non serve... al massimo gli causa solo un biciolo di sollievo... per esempio, quando apro il Blocco Note più volte, mi dà veramente fastidio che finisca sempre nello stesso posto? Boh, no... anche perché al momento di aprire la seconda istanza, nove su dieci ho già spostato la prima da un'altra parte... Comunque, vedi tu.
Una possibilità sarebbe ovviamente usare un registro (un file, se vogliamo) dove ogni istanza si iscrive al momento dell'apertura e si de-registra alla chiusura (è inutile segnare la posizione della finestra: tanto l'utente può cambiarla). Nota che non hai bisogno neppure di "dare un nome" a ciascuna istanza: se ogni istanza scrive semplicemente "aperta" quando si apre e "chiusa" quando si chiude, ti basta fare il conto di quante volte c'è scritto "aperta" e sottrarre le volte in cui c'è scritto "chiusa" per sapere quante istanze sono aperte in quel momento. A questo punto, ogni nuova istanza può guardare il registro, scoprire quante sorelle sono già aperte, e aprirsi in una posizione differente a seconda di un algoritmo che scegli (sempre consapevole del fatto che se nel frattempo l'utente ha spostato le finestre a modo suo, tutto questo a poco ti serve... ma vabbè). Mi sembra una soluzione molto macchinosa e fragile: per esempio, se un'istanza si chiude inaspettatamente e non ha modo di de-registrarsi... boh.
Una possibilità è mettersi a scoprire che cosa offre Windows per questo scenario (vedi le istanze multiple di calc.exe che si aprono in posti diversi)...
Una possibilità che mi sembra tutto sommato abbastanza elegante è far gestire l'apertura di una nuova istanza direttamente dal programma stesso... usando subprocess e degli argomenti della riga di comando per imporre la nuova posizione della finestra... Sarebbe macchinoso pure questo, ma mi sembra la soluzione più pulita. Magari domani ti scrivo una bozza di come si potrebbe fare.

Offline marcus72

  • python unicellularis
  • *
  • Post: 32
  • Punti reputazione: 0
    • Mostra profilo
Re:Tenere il conto delle istanze di uno script
« Risposta #4 il: Dicembre 29, 2018, 00:02 »
[...]Di conseguenza, se ritieni di dover supportare lo scenario "più versioni in esecuzione" (e non sto dicendo che sarebbe una buona idea... anzi), allora forse ti consiglio di supportarlo "da dentro il programma", non "da fuori". Ovvero, una sola istanza del programma che consente di aprire molteplici istanze della finestra, per esempio. Un po' come puoi aprire diversi documenti in un programma di videoscrittura.
Se riuscissi a fare questo, il problema è risolto, poiché basterebbe usare, nella classe che disegna la finestra con tkinter, una semplice variabile di classe, che conteggia il numero di istanze aperte (potrebbe essere un insieme set(); ogni istanza inizia a contare da 1. C'è 1 nel set? se no, allora io sono l'istanza 1; se sì, allora provo con 2). Avevo infatti iniziato la soluzione così, per poi rendermi subito conto che, facendo parte di processi diversi, ogni istanza aveva una variabile di classe diversa, quindi sempre impostata a 1.

Citazione
il mio programma, appena aperto legge lo stato precedente (un file di testo nel quale c'è la posizione della finestra sullo schermo, la sua dimensione e poche altre impostazioni), così all'apertura si trova esattamente come nell'ultima chiusura. Quando poi viene chiuso, controlla se lo stato è cambiato, e se lo è aggiorna il file relativo. Stop.
Ecco, questo (e solo questo!) è molto chiaro, e si chiama "persistere lo stato del programma". Puoi usare file di configurazione, database, pickle dump... quello che ti pare. Puoi persistere la posizione della finestra, l'ultimo documento aperto, le preferenze dell'utente... quello che vuoi. Fin qui è tutto molto chiaro ed è un pattern molto comune.
Il problema è che dopo aver scritto "Stop", tu invece non ti stoppi per niente e vai avanti a descrivere una situazione che è quasi sicuramente incompatibile con questa cosa semplice e comune che hai appena scritto. Ora, io non so di *quali* impostazioni tu stai parlando (dici "poche altre impostazioni", ma capisci... non è molto d'aiuto). Però pensaci nel caso generico:
- Apri l'istanza "A": questa registra in un file il suo status, e scrive "sono A e sono fatta così e così".
- Poi apri l'istanza "B", e questa fa la stessa cosa: "sono B, bla bla bla". Ovviamente fai anche tutto il tuo giro di danza che ti piace, per cui se B scopre che c'è già A aperta allora non va a mettersi proprio sopra A, etc. etc.
- Poi chiudi A, e A registra nel file di status che si è chiusa.
- Poi chiudi B, stessa cosa.
Adesso, quando vuoi aprire una nuova istanza... che cosa vuoi fare davvero? Aprire di nuovo A, aprire di nuovo B, oppure aprire qualcosa di vergine? Ovviamente puoi inventarti delle regole... anche molto strane e sofisticate... per esempio, se non c'è nessuna istanza già aperta allora vuoi aprire A, se A è già aperta allora apri una B, e se A e B sono entrambe già aperte, allora apri una nuova istanza vergine e la chiami C. Ma dopo un po', che cosa succede se l'utente vuole sbarazzarsi per sempre di B, e non vuole mai più aprirla? Boh. Eccetera eccetera.
Guarda, è impossibile che un utente voglia sbarazzarsi di B, semplicemente perché B è "lo stato della seconda finestra aperta". Se non vuole che stia nell'angolo in basso a destra, per esempio, sposterà la finestra da un'altra parte. Gli stati memorizzati semplicemente semplificano molto la vita perché al lavoro si ha l'abitudine di spostare le finestre sempre nella stessa zona. Gli stati memorizzati sono solo una facilitazione. Che però di volta in volta rendono più semplice e piacevole lavorarci.
 
Insomma, "persistere lo stato del programma" quando possono esserci più istanze del programma, è un po' un casino. Non importa che siano "solo poche impostazioni". Ti invito a rifletterci sopra a fondo.

Tuttavia, *se* quello che vuoi è davvero solo e semplicemente:
- che se c'è un'altra istanza aperta, allora quella nuova si sposta un po' più in là...
(ma nota bene: questo *NON* è affatto quello che hai detto)
No, infatti non voglio che semplicemente ogni istanza non si sovrapponga alle precedenti... Voglio che ci sia uno stato salvato per la prima istanza, un altro per la seconda, ecc.

[...]Una possibilità sarebbe ovviamente usare un registro (un file, se vogliamo) dove ogni istanza si iscrive al momento dell'apertura e si de-registra alla chiusura (è inutile segnare la posizione della finestra: tanto l'utente può cambiarla). Nota che non hai bisogno neppure di "dare un nome" a ciascuna istanza: se ogni istanza scrive semplicemente "aperta" quando si apre e "chiusa" quando si chiude, ti basta fare il conto di quante volte c'è scritto "aperta" e sottrarre le volte in cui c'è scritto "chiusa" per sapere quante istanze sono aperte in quel momento. A questo punto, ogni nuova istanza può guardare il registro, scoprire quante sorelle sono già aperte, e aprirsi in una posizione differente a seconda di un algoritmo che scegli (sempre consapevole del fatto che se nel frattempo l'utente ha spostato le finestre a modo suo, tutto questo a poco ti serve... ma vabbè). Mi sembra una soluzione molto macchinosa e fragile: per esempio, se un'istanza si chiude inaspettatamente e non ha modo di de-registrarsi... boh.
No, questa cosa non va bene perché se
1) apro A
2) poi apro B
3) chiudo A
B diventa la sola istanza aperta, per cui "diventa" A. Invece B resta B, e se poi
4) apro una nuova istanza, deve essere A (cioè deve caricare l'ultimo stato di A).
Per fare questo, ogni istanza (che è una classe di tkinter) inizializza il sul numero di istanza in __init__(self), per cui A si inizializza a 1, B si inizializza a 2, e quando chiudo A e poi riapro una istanza, si deve accorgere che l'istanza A (cioè con numero di istanza 1) non c'è, e quindi si inizializza a 1. Se eventualmente ne apro un'altra di istanza, avrà 1 e 2 già occupati, e si inizializzerà a 3 (diventando così C).
Quando istanzio la classe, gli passo il nome del file che contiene lo stato. Nell'inizializzazione, quindi, ogni istanza aggiungerà al nome il numero che ho detto prima, così che lo stato di A è, per esempio, "stato1.txt", quello di B è "stato2.txt", ecc.

Una possibilità è mettersi a scoprire che cosa offre Windows per questo scenario (vedi le istanze multiple di calc.exe che si aprono in posti diversi)...
Una possibilità che mi sembra tutto sommato abbastanza elegante è far gestire l'apertura di una nuova istanza direttamente dal programma stesso... usando subprocess e degli argomenti della riga di comando per imporre la nuova posizione della finestra... Sarebbe macchinoso pure questo, ma mi sembra la soluzione più pulita. Magari domani ti scrivo una bozza di come si potrebbe fare.
Non mi voglio concentrare su Windows. Fin'ora funziona tutto perfettamente sia in Linux che in Windows, e voglio continuare per questa strada. Ma credo che l'idea di avere un solo processo padre sia la strada più promettente. Potrei così usare una variabile di classe (come detto qui sopra), e sarebbe tutto più semplice.
Quindi la prima istanza lancia anche un server che visualizza la prima finestra in un processo separato, e resta in ascolto su socket. La seconda istanza si connette al socket, e ricevendo una risposta si chiude. Il server lancia così una seconda finestra in un processo separato. Così risolvo il primo problema che mi ero posto, cioè se si chiude una qualsiasi finestra il server non si chiude. Poi posso far chiudere il server se tutte le finestre si chiudono, o posso anche lasciare il server aperto fino allo spegnimento del pc... Deciderò poi.
Grazie mille per l'aiuto! Domani ci provo e ti aggiorno. :)

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 2.851
  • Punti reputazione: 9
    • Mostra profilo
Re:Tenere il conto delle istanze di uno script
« Risposta #5 il: Dicembre 29, 2018, 18:03 »
Citazione
Se riuscissi a fare questo, il problema è risolto, poiché basterebbe usare, nella classe che disegna la finestra con tkinter, una semplice variabile di classe, che conteggia il numero di istanze aperte (potrebbe essere un insieme set(); ogni istanza inizia a contare da 1. C'è 1 nel set? se no, allora io sono l'istanza 1; se sì, allora provo con 2). Avevo infatti iniziato la soluzione così, per poi rendermi subito conto che, facendo parte di processi diversi, ogni istanza aveva una variabile di classe diversa, quindi sempre impostata a 1.
"Facendo parte di due processi diversi"? No, chiaramente no. Se le finestre sono create dalla stessa (e unica) istanza dell'applicazione, allora fanno per forza parte dello stesso processo.
Piuttosto non è che hai qualche problema a ricordare come funzionano queste "semplici variabili di classe"? Per esempio:

>>> class Foo:
...  x = 0
...  def __init__(self):
...   self.x += 1
...
>>> f1, f2, f3 = Foo(), Foo(), Foo()
>>> f1.x, f2.x, f3.x  # non ci siamo....
(1, 1, 1)
>>>
>>> class Foo:
...   x = 0
...   def __init__(self):
...     Foo.x += 1
...
>>> f1, f2, f3 = Foo(), Foo(), Foo()
>>> f1.x, f2.x, f3.x  # dannazione, non ci siamo ancora
(3, 3, 3)
>>>
>>> class Foo:
...   x = 0
...   def __init__(self):
...     Foo.x += 1
...     self.x = Foo.x
...
>>> f1, f2, f3 = Foo(), Foo(), Foo()
>>> f1.x, f2.x, f3.x  # oh, finalmente
(1, 2, 3)

O anche, in modo più elegante https://stackoverflow.com/a/8628132 (anche se lo so, non è esattamente il modello che hai in mente tu... ma ci capiamo).

Detto questo, il problema è sempre avere ben presente il design. Un programma che consente più istanze della finestra principale è un design *molto diverso* da un programma che consente una sola istanza della finestra (ma che l'utente ha certamente facoltà di aprire più volte). SE un design "finestra multi-istanza" ha senso per il tuo programma, allora vai tranquillo. Ma ripeto, non farlo solo per la dubbia feature di spostare un po' più in là le finestre... non ha proprio senso, davvero.

Citazione
Guarda, è impossibile che un utente voglia sbarazzarsi di B, semplicemente perché B è "lo stato della seconda finestra aperta". Se non vuole che stia nell'angolo in basso a destra, per esempio, sposterà la finestra da un'altra parte. Gli stati memorizzati semplicemente semplificano molto la vita perché al lavoro si ha l'abitudine di spostare le finestre sempre nella stessa zona. Gli stati memorizzati sono solo una facilitazione. Che però di volta in volta rendono più semplice e piacevole lavorarci.
Occhei, suppongo, de gustibus.... Il problema naturalmente è che tu non vuoi solo memorizzare la posizione della finestra ma anche "qualche altra impostazione" (a quanto dici). E quindi, di nuovo, l'importante è che tu abbia ben chiaro (con carta-e-penna, davvero) che cosa vuol dire nel tuo caso "persistere e ripristinare gli stati di un diverse istanze gemelle della tua applicazione (o comunque della sua finestra principale)". Cerca di chiarirti bene che cosa implica, che cosa si aspetta l'utente, quali sono le ramificazioni. E fidati, *ci sono* delle ramificazioni.

Citazione
No, questa cosa non va bene perché se
1) apro A
2) poi apro B
3) chiudo A
B diventa la sola istanza aperta, per cui "diventa" A. Invece B resta B, e se poi
4) apro una nuova istanza, deve essere A (cioè deve caricare l'ultimo stato di A).
Ooooooooccccchei.... supppongo... cioè, mi sfugge completamente il principio razionale di questa interfaccia, e soprattutto non mi viene in mente nessun programma nel mondo reale che utilizzi una regola simile... Anzi, ti prego davvero di citarmi un esempio concreto che hai visto, perché proprio mi incuriosisce come principio di user experience.
Comunque, non è difficile implementare una cosa del genere... di fatto è una semplice lista del tipo
[True, True, False, True, .....]
Dove ogni True indica che la corrispondente istanza è attiva, e ogni False indica che è stata ormai chiusa. Ogni nuova istanza, al momento della creazione, percorre la lista fino a trovare il primo False (cioè, in pratica fa lista.index(False)), lo sostituisce con un True e da quel momento sa di essere l'istanza numero "n" (l'indice della lista). Se non trova nessun False vuol dire che tutte le istanze "storiche" sono già aperte, e quindi si accoda alla lista. Quando l'istanza si chiude, scrive di nuovo False nella lista, al suo indice.
Poi naturalmente c'è un altro oggetto globale (poniamo un dizionario) che salva le caratteristiche (posizione, etc.) delle varie istanze numerate:
status = {1: (100, 150, "blu", "legale buono"), 2: (230, 180, "verde", "neutrale malvagio"), 3: (250, 160, "giallo", "caotico neutrale"), ....}
Come poi fisicamente scegli di persistere tutte queste cose, boh, non importa. Può essere benissimo un pickle, per dire.
Ovviamente continuano a esserci molti dubbi sul senso di questo design, ma insomma, per fare si può fare.

Offline marcus72

  • python unicellularis
  • *
  • Post: 32
  • Punti reputazione: 0
    • Mostra profilo
Re:Tenere il conto delle istanze di uno script
« Risposta #6 il: Dicembre 30, 2018, 14:42 »
Citazione
Se riuscissi a fare questo, il problema è risolto, poiché basterebbe usare, nella classe che disegna la finestra con tkinter, una semplice variabile di classe, che conteggia il numero di istanze aperte (potrebbe essere un insieme set(); ogni istanza inizia a contare da 1. C'è 1 nel set? se no, allora io sono l'istanza 1; se sì, allora provo con 2). Avevo infatti iniziato la soluzione così, per poi rendermi subito conto che, facendo parte di processi diversi, ogni istanza aveva una variabile di classe diversa, quindi sempre impostata a 1.
"Facendo parte di due processi diversi"? No, chiaramente no. Se le finestre sono create dalla stessa (e unica) istanza dell'applicazione, allora fanno per forza parte dello stesso processo.
Piuttosto non è che hai qualche problema a ricordare come funzionano queste "semplici variabili di classe"? Per esempio:

>>> class Foo:
...  x = 0
...  def __init__(self):
...   self.x += 1
...
>>> f1, f2, f3 = Foo(), Foo(), Foo()
>>> f1.x, f2.x, f3.x  # non ci siamo....
(1, 1, 1)
>>>
>>> class Foo:
...   x = 0
...   def __init__(self):
...     Foo.x += 1
...
>>> f1, f2, f3 = Foo(), Foo(), Foo()
>>> f1.x, f2.x, f3.x  # dannazione, non ci siamo ancora
(3, 3, 3)
>>>
>>> class Foo:
...   x = 0
...   def __init__(self):
...     Foo.x += 1
...     self.x = Foo.x
...
>>> f1, f2, f3 = Foo(), Foo(), Foo()
>>> f1.x, f2.x, f3.x  # oh, finalmente
(1, 2, 3)

O anche, in modo più elegante https://stackoverflow.com/a/8628132 (anche se lo so, non è esattamente il modello che hai in mente tu... ma ci capiamo).
Sì, sì, so bene come funzionano le variabili di classe in Python... L'altro ieri notte, pensandoci, mi era venuto il sospetto che in processi diversi (anche se fratelli) non venisse mantenuto il valore delle variabili di classe, perché se son processi separati, la zona di memoria in cui si trovano deve essere diversa... Poi ieri non ho avuto la testa di programmare, e non ho scritto neanche una riga.
Ma, sinceramente, la soluzione scritta al volo qui non mi piaceva molto perché mi costringeva a dividere la logica della gestione di più istanze in due punti diversi, addirittura due file .py diversi... Molto meglio se è il server stesso ad assegnare ad ogni gui figlia un suo numero diverso, così da accentrare la logica tutta nel padre server.

Detto questo, il problema è sempre avere ben presente il design. Un programma che consente più istanze della finestra principale è un design *molto diverso* da un programma che consente una sola istanza della finestra (ma che l'utente ha certamente facoltà di aprire più volte). SE un design "finestra multi-istanza" ha senso per il tuo programma, allora vai tranquillo. Ma ripeto, non farlo solo per la dubbia feature di spostare un po' più in là le finestre... non ha proprio senso, davvero.
Guarda, quando avrò finito questo programma farò un video dimostrativo su Youtube, e magari se vedi questa mia idea ti sarà più chiara... È una cosa necessaria? No. È una cosa che penso faccia risparmiare tempo al lavoro? Sì, solo 5 o 10 secondi ogni volta che si apre, ma visto che lo sto testando in prima persona sono convinto che lo sforzo valga la pena.

Citazione
Guarda, è impossibile che un utente voglia sbarazzarsi di B, semplicemente perché B è "lo stato della seconda finestra aperta". Se non vuole che stia nell'angolo in basso a destra, per esempio, sposterà la finestra da un'altra parte. Gli stati memorizzati semplicemente semplificano molto la vita perché al lavoro si ha l'abitudine di spostare le finestre sempre nella stessa zona. Gli stati memorizzati sono solo una facilitazione. Che però di volta in volta rendono più semplice e piacevole lavorarci.
Occhei, suppongo, de gustibus.... Il problema naturalmente è che tu non vuoi solo memorizzare la posizione della finestra ma anche "qualche altra impostazione" (a quanto dici). E quindi, di nuovo, l'importante è che tu abbia ben chiaro (con carta-e-penna, davvero) che cosa vuol dire nel tuo caso "persistere e ripristinare gli stati di un diverse istanze gemelle della tua applicazione (o comunque della sua finestra principale)". Cerca di chiarirti bene che cosa implica, che cosa si aspetta l'utente, quali sono le ramificazioni. E fidati, *ci sono* delle ramificazioni.
Per "qualche altra impostazione" intendo: la dimensione dei caratteri (visto che con CTRL e +/- si può aumentare/diminuire la dimensione dei font usati, come su Firefox), lo status di una label (che può essere visualizzata per intero o abbreviata alla prima riga), e lo stato di tre checkbox (ognuno associato al comportamento della finestra, come per esempio la trasparenza o lo stare sempre in alto). Ho sorvolato perché non è importante ai fini di quello che mi serve. Infatti o memorizzo solo posizione e dimensione della finestra, o ci aggiungo anche queste altre impostazioni, il discorso è sempre lo stesso.

Citazione
No, questa cosa non va bene perché se
1) apro A
2) poi apro B
3) chiudo A
B diventa la sola istanza aperta, per cui "diventa" A. Invece B resta B, e se poi
4) apro una nuova istanza, deve essere A (cioè deve caricare l'ultimo stato di A).
Ooooooooccccchei.... supppongo... cioè, mi sfugge completamente il principio razionale di questa interfaccia, e soprattutto non mi viene in mente nessun programma nel mondo reale che utilizzi una regola simile... Anzi, ti prego davvero di citarmi un esempio concreto che hai visto, perché proprio mi incuriosisce come principio di user experience.
[\quote]
Questo comportamento non l'ho visto da nessuna parte, ma usandolo tutti i giorni al lavoro è quello che vorrei che faccia! Non per forza si deve copiare le idee altrui! E non sempre la farina del proprio sacco non è "roba buona"!
Ho iniziato questo progetto a fine luglio, partendo da un'esigenza che ho avuto al lavoro... a seguito di un problema (per la cui soluzione ho dovuto fare una telefonata o non avrei potuto proseguire la pratica che stavo facendo) ho pensato: "Non sarebbe difficile fare un programma che mi cerchi questa cosa...". Partendo da lì ho tirato fuori in un mese uno script che, già al mio primo giorno di lavoro, mi ha fatto risparmiare parecchio tempo! Poi giorno per giorno al lavoro pensavo "Mi piacerebbe che facesse anche questa cosa", e a casa la implementavo. Le cose che sto facendo adesso sono quelle che avevo messo in lista da fare (cioè con priorità più bassa), ma se voglio impiegarci tempo e fatica non è solo perché mi piace programmare, ma anche perché io stesso, da utilizzatore, so che mi fanno risparmiare tempo. E credimi, quando stai tante ore in un ufficio, anche se risparmi 5 secondi l'ora ci guadagni in stress più che in tempo (perché non sono tanto i 5 secondi, ma il fatto di dover ripetere gli stessi gesti che mi stressa).

Comunque, non è difficile implementare una cosa del genere... di fatto è una semplice lista del tipo
[True, True, False, True, .....]
Dove ogni True indica che la corrispondente istanza è attiva, e ogni False indica che è stata ormai chiusa. Ogni nuova istanza, al momento della creazione, percorre la lista fino a trovare il primo False (cioè, in pratica fa lista.index(False)), lo sostituisce con un True e da quel momento sa di essere l'istanza numero "n" (l'indice della lista). Se non trova nessun False vuol dire che tutte le istanze "storiche" sono già aperte, e quindi si accoda alla lista. Quando l'istanza si chiude, scrive di nuovo False nella lista, al suo indice.
Sì, ieri ci ho pensato che si poteva fare anche così. Appena mi ci metto vedo se è più semplice.

Poi naturalmente c'è un altro oggetto globale (poniamo un dizionario) che salva le caratteristiche (posizione, etc.) delle varie istanze numerate:
status = {1: (100, 150, "blu", "legale buono"), 2: (230, 180, "verde", "neutrale malvagio"), 3: (250, 160, "giallo", "caotico neutrale"), ....}
Come poi fisicamente scegli di persistere tutte queste cose, boh, non importa. Può essere benissimo un pickle, per dire.
Ovviamente continuano a esserci molti dubbi sul senso di questo design, ma insomma, per fare si può fare.
No, non serve a niente che il server sappia dove si trovano le varie finestre figlie... i tuoi dubbi su questa cosa sono più che sensati.
Ogni finestra, appena parte, deve solo sapere che numero è (se la prima, la seconda, ecc), per cui vede se ha uno stato da recuperare, ed in chiusura valuta da sola se deve salvare il suo stato.
Grazie ancora per il tempo che mi stai dedicando! :)

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 2.851
  • Punti reputazione: 9
    • Mostra profilo
Re:Tenere il conto delle istanze di uno script
« Risposta #7 il: Dicembre 30, 2018, 22:00 »
Citazione
Sì, sì, so bene come funzionano le variabili di classe in Python... L'altro ieri notte, pensandoci, mi era venuto il sospetto che in processi diversi (anche se fratelli) non venisse mantenuto il valore delle variabili di classe,
Beh sì è *ovvio* che se hai due processi python separati una variabile di classe non "vale" per entrambi... A meno che non stai sviluppando su un DOS anni '80, forse.
Citazione
Guarda, quando avrò finito questo programma farò un video dimostrativo su Youtube, e magari se vedi questa mia idea ti sarà più chiara... È una cosa necessaria? No. È una cosa che penso faccia risparmiare tempo al lavoro? Sì, solo 5 o 10 secondi ogni volta che si apre, ma visto che lo sto testando in prima persona sono convinto che lo sforzo valga la pena.
Non guardo le cose su YT. Siamo su un forum di programmazione, puoi sempre postare un esempio di codice. O caricarlo da qualche parte in rete, come fanno tutti quando vogliono far vedere del codice. Ma poi non era tanto una curiosità mia, quanto un invito per te a riflettere che se nessuno fa cose del genere, magari forse chissà una ragione ci sarà. Però intendiamoci, nessun problema. Il codice è tuo, il tempo per svilupparlo è tuo, il calcolo costi/benefici è tuo.
Citazione
Per "qualche altra impostazione" intendo: la dimensione dei caratteri (visto che con CTRL e +/- si può aumentare/diminuire la dimensione dei font usati, come su Firefox), lo status di una label (che può essere visualizzata per intero o abbreviata alla prima riga), e lo stato di tre checkbox (ognuno associato al comportamento della finestra, come per esempio la trasparenza o lo stare sempre in alto). Ho sorvolato perché non è importante ai fini di quello che mi serve. Infatti o memorizzo solo posizione e dimensione della finestra, o ci aggiungo anche queste altre impostazioni, il discorso è sempre lo stesso.
"Non è importante"? Mah, sì forse. E forse creerà delle user-experience un po' bizzarre, come ti invitavo a riflettere. Ma almeno non si tratta di settings legati alla logica di business... è già qualcosa.

Offline marcus72

  • python unicellularis
  • *
  • Post: 32
  • Punti reputazione: 0
    • Mostra profilo
Re:[RISOLTO] Tenere il conto delle istanze di uno script
« Risposta #8 il: Dicembre 30, 2018, 23:28 »
Grazie mille RicPol! Ho risolto, e funziona perfettamente!! Alla fine come contatore ho usato una lista, come mi avevi suggerito, in cui però ogni voce non è un bool ma il collegamento con il figlio del server (cioè n-esima istanza), così da poter sapere se è ancora in vita (quindi indipendentemente se la chiusura è stata regolare o "anomala").  :ok:
Se poi tutte le istanze sono state chiuse, il server si chiude a sua volta.
« Ultima modifica: Dicembre 30, 2018, 23:33 da marcus72 »