[python] Disegnare un fiocco di neve con OpenGL, Python e pygame

Visto che siamo in tema natalizio vediamo come disegnare un fiocco di neve con Python, OpenGL e pygame.

Questo esercizio riprende in parte quanto già visto per disegnare un poligono sempre con Python e OpenGL.

Anzitutto assicuriamoci di avere installate le librerie PyOpenGL e pygame, qualora non le avessimo sarà sufficiente installarle mediante pip con i seguenti due comandi:

Fatto questo possiamo cominciare a predisporre il nostro programma.

Anzitutto voglio fare un breve approfondimento su alcune funzioni che andremo ad utilizzare.

Cominciamo da gluPerspective. Questa funzione accetta 4 argomenti:

  • fovy: sostanzialmente l’angolo di visione in gradi, come illustrato nell’immagine di seguito
  • aspect ratio: il rapporto tra altezza e larghezza, sostanzialmente ci andiamo ad inserire il rapporto tra le dimensioni del nostro schermo (poi ne discutiamo meglio)
  • zNear: il piano più vicino dopo il quale comincia la visione
  • zFar: il piano più lontano al quale termina la visione
Risultato immagini per gluPerspective"
Immagine presa da GLUT and OpenGL by Robby T. Tan

Ricordiamoci che andremo a disegnare un oggetto in 3D, che dovrà essere posizionato all’interno del tronco di piramide definito dai due piani e dall’angolo di apertura. Se l’oggetto dovesse uscire da questo spazio semplicemente non risulterebbe visibile sullo schermo (o risulterebbe parzialmente tagliato). Da questo si capisce come l’angolo di apertura determinerà la prospettiva e lo spazio di interazione dell’oggetto. La situazione sostanzialmente è la seguente:

Per maggiori approfondimenti consiglio anche una lettura veloce a Perspective distortion (photography)

Dal momento che andrò a posizionare i nostri oggetti a partire da (0,0,0) voglio anche spostare il punto di visione (viewpoint) indietro, in modo da farceli entrare, altrimenti non sarebbero visibili. Per farlo utilizzo la funzione glTranslatef che prendere come argomenti i valori x, y e z sui quali effettuare la traslazione.

Infine voglio disegnare delle linee usando i rispettivi vertici. Per farlo dovrò aggiungere coppie di vertici alla “matrice del mondo” con il metodo glVertex3fv. Nel caso specifico posso disegnare una linea orizzontale che vada da (0,0,0) a (1,0,0) scrivendo le seguenti quattro righe di codice:

Se volessi disegnare un quadrato dovrei disegnare tutte le linee a coppie di vertici, nel modo seguente:

Sostanzialmente quello che facciamo in questo caso potrebbe essere riassunto col seguente schema:

Disegniamo le varie linee del quadrato seguendo le direzioni delle frecce rosse.

Adesso se volessimo limitarci a disegnare un quadrato e farlo ruotare davanti alla telecamera potremmo scrivere il seguente programma:

Grazie a glClearColor(0, 0, 0.1, 1) coloriamo lo sfondo di un blu scuro. Eseguendo il programma vedremo qualcosa di simile:

Il quadrato sarà in movimento ovviamente, grazie alla funzione glRotatef che ruota la matrice del mondo.

Arrivati a questo punto ci manca solo di disegnare il fiocco di neve, ovvero preparare le coppie di vertici di tutte le linee del fiocco di neve stesso.

Per farlo voglio seguire il seguente schema:

Partiamo dal basso e disegniamo un ramo di lunghezza L. Prendiamo come riferimento un angolo α di 45° (ovvero π/4). Alla fine del ramo teniamo conto dell’angolo di arrivo e disegniamo altri due rami, ciascuno spostato di 45°. Procediamo in avanti ripetendo questo schema per n iterazioni.

Creiamo quindi due classi, una per il Fiocco e una per ciascun Ramo, nel modo seguente (nei commenti in Python ulteriori dettagli):

Fatto tutte questo reintegriamo il tutto nella nostra classe iniziale FioccoDiNeve.

Se abbiamo fatto tutto correttamente otterremo il nostro fiocco di neve frattale ruotante in questo modo:

Vedi articolo

[python] Utilizzare Python su Apache (configurazione con XAMPP)

Anzitutto assicuriamoci di avere Python installato sul nostro computer. Nel mio esempio procederò con l’installazione su Windows, ma anche nel caso di un server Linux la procedura è pressoché la medesima.

1. Individuiamo la cartella di installazione di Python

Nel mio caso l’eseguibile di Python si trova in D:/Python27/python.exe

Appuntiamoci questo valore perché ci servirà per dopo.

2. Configuriamo Apache modificando il file httpd.conf

Utilizzando XAMPP è sufficiente aprire il pannello di controllo e recarsi su Apache > Config > Apache (httpd.conf)

3. Aggiungiamo il handler per gli script cgi

In fondo al file di configurazione aggiungiamo le seguenti due righe per attivare la gestione degli script cgi

In questo modo permettiamo ad apache di interpretare i file con estensione .py come script eseguibili mediante applicazioni interne al computer.

4. Aggiungiamo index.py alle pagine di default

Esattamente per quello che succede per index.htm oppure index.php, vogliamo che anche index.py venga letta come pagina predefinita di una cartella. (potremmo metterne anche altre a piacere)

Per farlo modifichiamo sempre il file httpd.conf che abbiamo aperto prima. Identifichiamo il punto dove c’è scritto <IfModule dir_module> e modifichiamo la configurazione nel modo seguente, aggiungendo index.py all’elenco

5. Riavviamo apache

Che lo si stia facendo su XAMPP, oppure su un server LAMP, a questo punto riavviamo Apache, banalmente premendo Stop e Start in sequenza.

6. Creiamo la prima pagina in Python

Dentro la cartella htdocs creiamo una cartella a piacere, che allo scopo di questo esempio io chiamerò python.

Dentro la cartella creiamo un file chiamato index.py con dentro le seguenti istruzioni:

Ricordiamoci l’indirizzo preso all’inizio al punto 1. Il percorso di installazione di Python andrà incluso in ciascun file. Inoltre è essenziale il primo print, che permette al browser di interpretare il contenuto come una pagina html.

Le prime 2 righe dovranno essere presenti in ogni pagina che si occuperà dell’output.

7. Esempio di una pagina semplice

Ovviamente dovremo aggiungere tutti gli opportuni tag del HTML, cosa che potremmo fare in questo modo:

8. Raccogliere i dati da POST e GET

Infine vediamo come raccogliere i dati dai due metodi principali con i quali l’utente può interagire con la nostra pagina web, il get e il post.

Per farlo importiamo anzitutto la libreria CGI aggiungendo in cima al file, dopo il percorso all’eseguibile di Python, import cgi

Avremo bisogno anche di gestire eventuali errori che se no non verranno mostrati nell’output. Per farlo importiamo anche cgitb aggiungendo le seguenti due righe:

L’intestazione del nostra file diventerà:

A questo punto per raccogliere i dati, sia da POST che da GET utilizziamo l’istruzione dati = cgi.FieldStorage()

Modifichiamo tutta la pagina per funzionare con un piccolo form che utilizzi entrambi i metodi:

Faccio notare che se si cerca di chiamare la pagina http://127.0.0.1/python/?dati_form=1 si incorrerà in un errore come il seguente (senza la suddetta libreria avremmo visualizzato una pagina bianca):

Questo perché la chiave valore non è definita all’interno del contenitore dati.

Aggiungiamo quindi un controllo nel modo seguente:

 

Vedi articolo

[python] Recuperare i messaggi cancellati definitivamente da un file *.pst di Outlook

Outlook salva tutto il contenuto dell’account di posta dentro ad un file *.pst che viene trattato similmente ad uno spazio sul disco. Questo significa che quando un messaggio viene cancellato definitivamente (per esempio svuotando il cestino oppure cancellandolo con SHFIT+CANC) in realtà non viene rimosso definitivamente dal file, ma ne rimane traccia finché un nuovo messaggio non andrà a sovrascriverlo. Questa non è una spiegazione perfettamente accurata, ma è quanto ci serve sapere allo scopo.

Per recuperare un messaggio cancellato definitivamente è anzitutto importante non scaricare o inviare nuovi messaggi, non fare cioè alcuna operazione che potrebbe modificare il file *.pst.

Detto questo possiamo tentare di recuperare i dati modificando alcuni byte del file *.pst e utilizzando il programma Scanpst.exe fornito assieme ad Office. Dalla versione Microsoft Office 2016 il programma è eseguibile anche tramite linea di comando.

Vediamo quindi come creare un programma in python che ci permetta di effettuare le due operazioni recuperando quindi i messaggi.

Prima di procedere creiamo una copia del file *.pst per non provocare altri danni.

Quello che dobbiamo fare ora è modificare, mettendoli per esempio a 0, i primi 13 byte a partire dalla 7^ posizione nel file *.pst in questione. Questo farà sì che Scanpst.exe identifichi il file come corrotto e cerchi di recuperare i messaggi perduti. Usando un editor esadecimale, tipo Hex Edit, dovremmo vedere una situazione come la seguente.

Quelli che vogliamo mettere a 0 sono i byte evidenziati. Io lo farò usando python. Creiamo un vettore di byte a zero nel modo seguente:

Questo produrrà un vettore di byte che possiamo visualizzare con print( byte_vuoti )

Scriviamo il pezzo di codice necessario per modificare il file *.pst

Con fp.seek(7) ci posizioniamo sull’ottavo byte, e poi scriviamo i 13 byte a 0 dalla posizione acquisita.

Adesso passiamo il file a Scanpst.exe, potremmo farlo anche a mano, ma nel mio esempio lo farò tramite linea di comando.

Modifichiamo il codice soprastante nel modo seguente:

Per maggiori dettagli sui parametri da passare a Scanpst.exe rimando alla pagina ufficiale sul sito della Microsoft: Lo strumento Manutenzione Posta in arrivo (Scanpst.exe) può eseguire controlli multipli in Outlook 2016

Con os.path.dirname(os.path.realpath(__file__)) prendiamo la posizione del programma in python, laddove io suppongo che il file Outlook si trovi nella medesima cartella del programma. Inutile dire che file_pst = dir_path + "\\Outlook.pst" dipende dalla posizione del file *.pst che potremmo passare anche con il percorso diretto.

Con la riga scanpst = "C:\\Program Files (x86)\\Microsoft Office\\root\\Office16\\SCANPST.EXE" prendiamo la posizione del file Scanpst.exe che nel mio caso ha quel percorso. Anche questo dipende dalla nostra specifica installazione di Office. Ricordiamoci che questo procedimento è valido solo per le versioni di Office 2016 e successive.

Infine con output = os.popen(cmd).read() mettiamo il programma in attesa finché non verrà completata l’esecuzione del comando. (verrà scritto Fatto!)

Alla fine, se tutto è andato bene, dovremmo vedere qualcosa di questo genere nella cartella del file:

Per visualizzare di nuovo il contenuto del file *.pst è sufficiente collegarlo tra i File dati di Outlook.

Vedi articolo

[python] Esercizio su wxPython e PyOpenGL per disegnare un poligono dato il numero di lati

Quello che voglio realizzare oggi è un semplice programma in Python 2.7, con interfaccia grafica e che permetta di disegnare un poligono regolare dato il numero di lati. In questo esercizio vedremo quindi due cose:

  1. L’utilizzo di wxPython per creare un rudimentale programma con interfaccia grafica
  2. L’utilizzo di PyOpenGL per disegnare dentro ad un canvas una figura geometrica

Il programma che andremo a creare avrà alla fine questo aspetto, con uno spazio per inserire il numero di lati ed un canvas su cui disegnare:

Anzitutto assicuriamoci di disporre di entrambe le librerie, per farlo installiamole con pip eseguendo i seguenti due comandi da terminale:

Una volta installate le librerie possiamo cominciare a creare il nostro programma.

Per prima cosa creiamo una classe per la nostra applicazione, utilizzando wx.Frame e avviando la finestra principale. Il codice di cui avremo bisogno sarà il seguente:

In questo modo creiamo una finestra di dimensione 800 x 600 px con titolo Disegnatore. La nostra applicazione è un’estensione di wx.Frame, laddove un Frame è una finestra le cui dimensioni e posizione possono essere modificate dall’utente (insomma la classica finestra in Windows). Inoltre essa può contenere una barra del titolo, dei menu, dello stato e degli strumenti.

Con wx.App avviamo invece l’applicazione vera e propria, questa classe ci serve per lanciare il contenitore principale dell’applicazione e passiamo come argomento False (che sarebbe così anche di predefinito) per non reindirizzare lo sys.stdout e lo sys.stderr. Per maggiori informazioni rimando alla guida ufficiale su App.

A questo punto voglio aggiungere la casella di testo e il pulsante per impostare il numero di lati. Per farlo dobbiamo usare un wx.Panel, che sostanzialmente è il contenitore degli elementi di controllo e si trova tipicamente dentro un Frame. Per maggiori informazioni leggere qui su Panel.

Modifico quindi il codice nella maniera seguente:

E’ molto importante che il Panel venga istanziato prima del metodo aggPulsanti che poi aggiunge elementi al Panel. Arrivati a questo punto lanciamo il nostro programma e verifichiamo che abbia il seguente aspetto.

A questo punto è l’ora di aggiungere anche il Canvas che ci permetterà di mostrare grafica in OpenGL. Per farlo includiamo anzitutto le librerie necessarie:

Modifichiamo poi il codice nel modo seguente:

E’ importante stabilire le dimensioni del canvas in due variabili s.width e s.height per delle correzioni che apporteremo successivamente, per ora prendiamola per buona così.

A questo punto inizializziamo il canvas aggiungendo le seguenti istruzioni:

Faccio notare che il metodo glClearColor(1, 1, 1, 1) imposta il colore dello sfondo su bianco, mentre il metodo glClearColor(0, 0, 0, 1) lo imposta su nero. I primi tre parametri sono i valori di RGB da 0 a 1.

Siamo arrivati a buon punto e siamo praticamente pronti a disegnare il nostro poligono. Il nostro riferimento è uno spazio cartesiano con gli assi che attraversano a metà il canvas e il punto (0, 0) al centro del canvas stesso. Un poligono regolare ha tanti vertici quanti i lati e ogni vertice poggia su una circonferenza di raggio r.

Questo significa che un angolo α che passa da un vertice all’altro è dato dalla seguente equazione:

\alpha = 2 * \pi / n

Dove n è il numero di lati (o vertici) del poligono. Traduciamo questa formula in Python nel modo seguente:

Avremo bisogno della libreria math che importiamo con:

L’angolo di partenza è arbitrario, però per far sì che il lato superiore del poligono sia parallelo all’asse delle ascisse voglio prendere come angolo di partenza:

\beta = \pi / 2 - \pi / n

Quindi la nostra formula sarà:

Attenzione ad inserire i numeri con almeno una cifra decimale, anche se zero, per assicurarci che Python esegua tutti i calcoli con valori decimali e non tronchi ad interi.

Infine vogliamo definire un raggio fisso per i nostri poligoni, per farlo userò come riferimento l’apotema a (anche se sarebbe sufficienti lato e raggio) nel modo seguente:

apotema = 0.5

lato = apotema * ( 2.0 * \tan( \pi / n ) )

raggio = \sqrt{ (lato/2)^2+apotema^2 }

Il primo vertice avrà quindi coordinate:

( raggio * \cos( \beta ) , raggio * \sin( \beta ) )

Il secondo vertice sarà:

( raggio * \cos( \beta + \alpha ) , raggio * \sin( \beta + \alpha ) )

Il terzo vertice sarà:

( raggio * \cos( \beta + 2 * \alpha ) , raggio * \sin( \beta + 2 * \alpha ) )

E così via.

Traduciamo il tutto nel seguente metodo:

Spostiamoci sul metodo onDraw e modifichiamolo nel modo seguente:

Nel costruttore __init__ della classe aggiungiamo una variabile s.n per il numero di lati, subito dopo le dimensioni del canvas, nel modo seguente:

Se abbiamo fatto tutto correttamente dovremmo vedere qualcosa come questo:

Notiamo subito che il pentagono è deformato ed inoltre manca la possibilità di definire una dimensione a piacere.

Anzitutto occupiamoci della deformazione, essa dipende dal fatto che il canvas ha una dimensione fissa di 1 x 1, che poi viene ripartita in parti decimali. Quindi tale dimensione si adatta poi alle proporzioni del canvas. Per ottenere un pentagono regolare anzitutto dobbiamo introdurre un fattore correttivo, che nel nostro caso sarà dato da:

Aggiungiamo la variabile subito dopo larghezza e altezza impostate in __init__.

Modifichiamo il metodo per disegnare il poligono nel modo seguente:

Adesso il poligono risulta regolare:

Infine attribuiamo un valore personalizzato al numero di lati s.n del poligono. Aggiungiamo i seguenti due metodi alla nostra classe:

E dove abbiamo istanziato s.pulsante aggiungiamo:

In questo modo colleghiamo il metodo s.btn_calcola all’evento wx.EVT_BUTTON che corrisponde alla pressione del pulsante. Con il metodo verificaIntero controlliamo se il valore passato dall’utente sia intero. Se non è intero mostriamo, grazie a wx.MessageBox, un messaggio a video con notifica di errore.

Se abbiamo fatto tutto correttamente otterremo il seguente codice finale:

Se lo eseguiamo abbiamo il nostro programma che ci permetterà di disegnare qualunque poligono regolare:

Vedi articolo

[python] Esercizio su utilizzo di socket e database

Proviamo a realizzare questo semplice esercizio: vorrei avere un server ed un client che possano comunicare tramite socket, in modo tale che il client possa richiedere al server dei dati, il server preleverà tali dati da un database MySQL e li invierà al client.

Lo schema dell’esercizio è approssimativamente questo:

Per svolgere l’esercizio utilizzerò un database con una tabella clienti costruita nel modo seguente:

In aggiunta utilizzerò una classe MySQLdb personalizzata, sviluppata nel modo seguente e messa nel file database.py:

La cartella dell’intero progetto sarà organizzata nella maniera seguente:

client.py
librerie
└── database.py
└── __init__.py
server.py

Fatte queste premesse andiamo anzitutto a creare il nostro file server.py. Nel codice ho inserito i commenti ai vari passaggi:

Adesso è il momento del client.py.

I risultati che dovremmo vedere sono rispettivamente:

1. Per il server vedo quando è stato avviato, da dove e da quale porta

2. Sul client vedo l’elenco presente sul database.

Vedi articolo

[python] Esercizio su funzioni ricorsive e calcolo tratte dei treni

Facciamo un piccolo programma in Python che ci permetta di gestire le distanze da percorrere tra due stazioni, di partenza ed arrivo.

Abbiamo le seguenti tratte:

Stazione A Stazione B Distanza
Firenze Bologna 100km
Firenze Roma 250km
Roma Napoli 200km
Bologna Milano 220km
Bologna Venezia 150km

Ogni tratta è percorribile sia in andata che in ritorno. Quello che vogliamo è che il programma ci permetta di inserire due città e calcolare la distanza minima da percorrere e le stazioni da attraversare.

Anzitutto vediamo come sono disposti i nodi dell’intero percorso:

Notiamo che in questa configurazione elementare solo Bologna ha 3 rami, mentre tutte le altre città hanno solo 2 rami ciascuna.

Potremmo affrontare l’esercizio lavorando sui nodi oppure sulle tratte. In questa soluzione lavorerò sulle tratte.

Cominciamo quindi creando anzitutto una classe che ci permetta di descrivere ogni tratta come abbiamo visto nel mandato dell’esercizio.

In questo modo dichiariamo 3 variabili private per registrare le due città della tratta e la rispettiva distanza.

Adesso registriamo tutte le tratte in una lista, nel modo seguente:

Ora cominciamo a pensare all’algoritmo che potrebbe permetterci di calcolare il percorso.

Immaginiamo anzitutto la soluzione più semplice, dove io penso di andare da Firenze a Napoli. Su questa tratta non ci sono diramazione e sostanzialmente il percorso che dovrà venire fuori sarà Firenze – Roma – Napoli.

Fase 1:

Faccio un ciclo su ogni elemento della lista tratte[] e cerco anzitutto dove è presente la città di partenza. Siccome la città può essere sia in A che in B, per ogni oggetto Tratta dovrò implementare un metodo all’interno dell’oggetto stesso che mi permetta di valutare se la città sia presente in modo comodo. Implementiamo quindi la classe nel modo seguente:

Il metodo presente(citta) mi permette di valutare se la città sia presente nella tratta.

Fase 2:

Se trovo la città di partenza su una tratta allora controllo se l’altra città della tratta sia quella di arrivo. Allo stesso tempo registro la città di partenza all’interno di una lista percorso[] in modo da metterla come partenza del percorso complessivo.

Quindi se l’altra città è quella di arrivo posso chiudere il percorso, altrimenti passo il controllo sull’altra città.

Quando mi trovo nella riga 10 capisco anche che ho trovato la fine del percorso, quindi posso salvare l’intero percorso da qualche parte. Siccome potrei avere molteplici percorsi possibili decido di salvare il percorso in una lista globale chiamata percorsi = []

Modifichiamo quindi il codice nel modo seguente:

Adesso analizziamo due aspetti dell’ultima istruzione, quella dove richiamo la funzione.

Anzitutto voglio tirare fuori dalla tratta l’altra città, rispetto alla città di partenza. Per farlo implemento la classe principale nel modo seguente:

In questo modo quando mi trovo per esempio sulla tratta Firenze – Roma posso passare all’oggetto tratta Firenze, che conosco essendo il punto di partenza e chiedergli di darmi l’altra città della tratta, in questo caso Roma.

Il secondo aspetto che voglio evidenziare è che passo la lista percorso[] alla funzione medesima in partenza dall’altra città, per farlo utilizzo l’istruzione []+percorso, in caso contrario percorso passerebbe per riferimento e qualora fosse passato su più rami verrebbe elaborato contemporaneamente da più rami. Io invece voglio che resti un oggetto singolo e lineare per ogni percorso.

Arrivati a questo punto del codice la situazione è la seguente:

  1. Prendo in input partenza DA = Firenze e A = Napoli
  2. Aggiungo DA (Firenze) al percorso[]
  3. Passo a setaccio la lista delle tratte[]
  4. In posizione 0 trovo la tratta Firenze – Bologna a cui DA appartiene
  5. Controllo se A (Napoli) appartiene alla tratta
  6. Dal momento che non appartiene, prendo l’altra città della tratta, ovvero Bologna e la passo come nuovo DA alla funzione medesima
  7. La funzione ricomincia e aggiungendo DA (Bologna) al percorso[]
  8. Scorro la lista delle tratte[] in cerca di DA (Bologna)
  9. Trovo che DA nella posizione 0 sulla tratta Firenze – Bologna
  10. LOOP INFINITO!

Fase 3:

Devo evitare il loop infinito in cui il percorso possa tornare indietro. Per farlo modifico la mia funzione aggiungendo il seguente controllo all’inizio:

In questo modo controllo che il punto di partenza DA non sia già presente nel percorso[].

Adesso ricomincio a controllare il mio algoritmo da capo:

  1. Prendo in input partenza DA = Firenze e A = Napoli
  2. Aggiungo DA (Firenze) al percorso[]
  3. Passo a setaccio la lista delle tratte[]
  4. In posizione 0 trovo la tratta Firenze – Bologna a cui DA appartiene
  5. Controllo se A (Napoli) appartiene alla tratta
  6. Dal momento che non appartiene, prendo l’altra città della tratta, ovvero Bologna e la passo come nuovo DA alla funzione medesima
  7. La funzione ricomincia e aggiungendo DA (Bologna) al percorso[]
  8. Scorro la lista delle tratte[] in cerca di DA (Bologna)
  9. Trovo che DA nella posizione 0 sulla tratta Firenze – Bologna
  10. L’altra città (Firenze) è uguale ad A? No, quindi ripasso l’altra città come nuovo DA alla funzione medesima
  11. La funzione si interrompe, perché DA (Firenze) è già presente in percorso[]
  12. Torno al punto 9
  13. In posizione 3 trovo Bologna – Milano dentro tratte[] dove appartiene il mio DA
  14. Questo pezzo di codice adesso si ripete uguale a quello tra 10 e 12 fino a chiudersi su Milano e Venezia che terminano il percorso
  15. Trono al punto 3
  16. In posizione 1 trovo la tratta Firenze – Roma a cui DA (Firenze) appartiene
  17. Controllo se A (Napoli) appartiene alla tratta
  18. Dal momento che non appartiene, prendo l’altra città della tratta, ovvero Roma e la passo come nuovo DA alla funzione medesima
  19. La funzione ricomincia e aggiungendo DA (Roma) al percorso[]
  20. Scorro la lista delle tratte[] in cerca di DA (Bologna)
  21. Trovo che DA nella posizione 1 sulla tratta Firenze – Roma
  22. L’altra città (Firenze) è uguale ad A? No, quindi ripasso l’altra città come nuovo DA alla funzione medesima
  23. La funzione si interrompe, perché DA (Firenze) è già presente in percorso[]
  24. Torno al punto 20
  25. Trovo che DA nella posizione 2 sulla tratta Roma – Napoli
  26. Controllo se A (Napoli) appartiene alla tratta
  27. Napoli appartiene alla tratta nel pezzo di codice if t.presente(a)
  28. A questo punto aggiungo A (Napoli) alla fine di percorso[]
  29. Aggiungo il percorso[] ai percorsi[] con l’istruzione percorsi.append(percorso)

Fase 4:

Apporto ancora un paio di correzioni tecniche alla mia funzione per evitare inutili duplicati.

A questo punto posso scrivere la parte principale del mio programma con:

Per stampare il percorso faccio una join su ogni percorso che trovo dentro a percorsi[]

Fase 5:

Aggiungo soltanto un metodo per calcolare le distanze. Potrei farlo anche in modi più ottimizzato, ma per le finalità di questo esercizio ci accontentiamo di percorrere tutte le stazioni, esclusa l’ultima, e di calcolare la distanza tra la stazione corrente e la successiva sommandole tutte insieme.

A tale proposito aggiunto un metodo che mi permetta di valutare se 2 città appartengono entrambe alla tratta ed un getter per la distanza.

La funzione quindi sarà:

Fatto tutto questo posso completare il mio programma nella sua versione finale nel modo seguente:

Se volessimo complicare un po’ lo schema potremmo aggiungere altre tratte:

Ed ottenere una versione finale del programma in questo modo:

Il nostro nuovo programma genererà un output come questo:

Vedi articolo

[python] File CSV o di testo comincia con  oppure con i byte EF BB BF

Facendo il parsing di un file CSV in python ci si potrebbe accorgere che all’inizio del file rimangono dei “segni strani”, nel mio caso ï»¿ (ma ciò dipende dalla formattazione con cui si visualizza).

Si tratta del Byte Order Mark (BOM), una piccola sequenza di caratteri che serve ad indicare la codifica Unicode del file medesimo.

Aprendo il file con un editor esadecimale, come HexEdit per esempio, vedremmo qualcosa come questo:

Nello specifico questo è un file esportato da WooCommerce e come primi 3 byte i valori EF BB BF che rappresentano l’UTF8.

Di seguito l’elenco, scopiazzato da Wikipedia, delle codifiche possibili:

Encoding Representation (hexadecimal) Representation (decimal) Bytes as CP1252 characters
UTF-8 EF BB BF 239 187 191 
UTF-16 (BE) FE FF 254 255 þÿ
UTF-16 (LE) FF FE 255 254 ÿþ
UTF-32 (BE) 00 00 FE FF 0 0 254 255 ^@^@þÿ (^@ is the null character)
UTF-32 (LE) FF FE 00 00 255 254 0 0 ÿþ^@^@ (^@ is the null character)
UTF-7 2B 2F 76 38
2B 2F 76 39
2B 2F 76 2B
2B 2F 76 2F
2B 2F 76 38 2D
43 47 118 56
43 47 118 57
43 47 118 43
43 47 118 47
43 47 118 56 45
+/v8
+/v9
+/v+
+/v/
+/v8-
UTF-1 F7 64 4C 247 100 76 ÷dL
UTF-EBCDIC DD 73 66 73 221 115 102 115 Ýsfs
SCSU 0E FE FF 14 254 255 ^Nþÿ (^N is the “shift out” character)
BOCU-1 FB EE 28 251 238 40 ûî(
GB-18030 84 31 95 33 132 49 149 51 „1•3

Per interpretare correttamente il contenuto del file è sufficiente decodificarlo nella codifica corretta, nel mio caso con:

Vedi articolo

[python] Radiazione di Hawking e tempo che impiega un buco nero ad evaporare

In memoria di Stephen Hawking propongo un modesto esercizio in Python per calcolare il tempo di evaporazione di un buco nero, secondo la radiazione di Hawking.

In questo caso utilizzeremo le librerie scipy e numpy di Python.

Il mio esempio sarà fatto sotto Windows. Anzitutto installiamo quindi le librerie necessarie utilizzando pip, nella PowerShell digitiamo:

Una volta fatto avviamo un nuovo progetto in python e andiamo anzitutto a calcolare la suddetta formula. L’equazione di evaporazione di un buco nero, che si trovasse in una condizione ideale (ovvero nessuna aggiunta di energia, quindi ipoteticamente in un universo completamente vuoto e senza radiazione di fondo) è la seguente:

t_{ev} = \frac{5120 \pi G^2 M_0^3}{\hbar c^4}

Per scriverla in Python digitiamo:

Faccio notare che da scipy importiamo le costanti fisiche e matematiche che possiamo utilizzare secondo la seguente tabella.

M0 è l’ipotetica massa iniziale di un buco nero di massa solare, nello specifico di 1,98892 * 10^{30} kg .

Il risultato dovrebbe essere:

Il risultato è in secondi, possiamo convertirlo in miliardi di anni digitando:

Il risultato è qualcosa come 2 * 10^{58} miliardi di anni, molto più dell’attuale vita dell’universo stimata attorno ai 13 miliardi di anni.

Adesso proviamo ad inserire l’equazione in un grafico, dove vogliamo confrontare vari tipi di buco nero in base alla massa ed il tempo di evaporazione.

Per farlo anzitutto convertiamo la nostra precedente equazione in una funzione digitando:

Ricordiamoci che il risultato della funzione è in secondi. A questo punto prepariamo i valori del nostro asse x, che saranno le masse di diversi buchi neri. Prendiamo 100 valori tra 0 e 1030.

Sull’asse Y calcoliamo i corrispondenti valori:

Adesso impacchettiamo tutto in un grafico generato con matplotlib.

Il risultato sarà qualcosa di simile a questo:

Vedi articolo