Ripristinare lo stato delle variabili locali in Python

Esempio istruttivo che mostra come cancellare variabili in un programma Python
Quanto leggerete qui di seguito vi mostrera' alcune tecniche che raramente userete in codice di produzione, ma nonostante tutto sono di indubbio interesse le enormi potenzialita' che il linguaggio di programmazione mette a disposizione dei suoi utenti.


Utilizzeremo in questo esempio, una shell Python interattiva, ma il codice funzionera' altrettanto bene se lanciato dall'interprete.
Il nostro scopo e' definire un numero indefinito di nuove variabili e poi cancellarle. E' possibile ottenere un dizionario delle variabili locali usando la funzione builtin locals.
Subito dopo aver avviato la shell fotografiamo lo stato delle variabili locali, salvando le chiavi di suddetto dizionario in una variabile di nome oldlocals.

>>> oldlocals=locals().keys()

Definiamo ora alcune variabili nuove.

>>> a,b,c,d = 1,2,3,4

Il contenuto di locals sara' diversi ora:

>>> newlocals=locals().keys()
>>> oldlocals
['__builtins__', '__file__', '__name__', 'readline', 'rlcompleter', '__doc__']
>>> newlocals
['a', 'oldlocals', 'b', 'd', '__builtins__', '__file__', 'c', '__name__', 'readline', 'rlcompleter', '__doc__']

Per cancellare le variabili definite dopo la nostra "foto" possiamo usare le funzioni insiemistiche del tipo set.

>>> newly_defined=set(newlocals).difference(oldlocals).difference(set(('oldlocals',)))
>>> newly_defined
set(['a', 'c', 'b', 'd'])
>>> a,b,c,d
(1, 2, 3, 4)

Ora andiamo a cancellare le variabili che siamo andati a definire.

>>> for var in newly_defined: del(locals()[var])
...
>>> a,b,c,d
Traceback (most recent call last):
File "", line 1, in
NameError: name 'a' is not defined
>>>

Perfetto, ora le variabili a,b,c e d sono libere!

Il discorso si potrebbe approfondire con risvolti molto interessanti: ad esempio potrete eliminare solo le variabili di un determinato tipo o le istanze di una certa classe.
Lascio a voi tutto il divertimento.

Python nose: scrivere test senza fatica per il nostro codice

Presto o tardi chi scrive codice deve fare i conti con imprevisti!
Uno dei modi per evitare sorprese e' quello di testare il codice scrivendo dei test che ne confermino la validita' di funzionamento.

Chi scrive codice in Python potra' giovarsi dalle comodita' offerte da Python Nose per scrivere test senza grossa fatica. La particolarita' di Python Nose e' che riesce a scovare le funzioni e le classi di test nel codice basandosi sul loro nome e senza bisogno di importare moduli esterni.

Per esempio...

Supposto che abbiate installato nose, andiamo a cimentarci con una funzione molto semplice ma che puo' riservare sorprese!
Guardate qua:
def fattoriale(n):
"""Funzione ricorsiva per il calcolo del fattoriale di un mnumero
"""
if n == 0:
return 1
else:
return fattoriale(n-1)*n
Che ne pensate? A prima vista sembra scritta bene, ma in realta' riserva qualche sorpresa.
Prima di tutto siamo sicuri funzioni?

Per esserne certi salviamo questa funzione in un file con estensione ".py" e aggiungiamo ad essa una prima funzione di validazione che controlli che i risultati siano corretti.
Affinche' nose si accorga della funzione di test, il suo nome dovra' contenere il prefisso "test" (geniale! :)). Il concetto e' che il test avra' successo la funzione ritornera' dei valori coerenti con quelli che sono calcolabili per altra via. Ad esempio i fattoriali dei numeri 0,1,2,3,4,5 corrispondono ai valori 1,1,2,6,24 e 120.
E' ovvio che se troviamo risultati diversi da questi significa che qualcosa nella funzione non torna.

La funzione che fa il test assomigliera' a questa:
def test_fattoriale():
"""Funzione invocata per testare la correttezza nel calcolo
"""
checks = (1,1,2,6,25,120)
for i, check in enumerate(checks):
f = fattoriale(i)
assert f == check,\
"Il fattoriale di %s e' %s" % (f, check)
Come vedete definiamo nella variabile checks i valori "corretti" e li confrontiamo con quelli che andremo a calcolare con la nostra fantastica funzione!

Il vostro file, fatto questo, assomigliera' a questo:

#!/usr/bin/env python
def fattoriale(n):
"""Funzione ricorsiva per il calcolo del fattoriale di un mnumero
"""
if n == 0:
return 1
else:
return fattoriale(n-1)*n

def test_fattoriale():
"""Funzione invocata per testare la correttezza nel calcolo
"""
checks = (1,1,2,6,25,120)
for i, check in enumerate(checks):
f = fattoriale(i)
assert f == check,\
"Il fattoriale di %s e' %s" % (f, check)
E' arrivato il momento della verita'!!!
Per lanciare il test date il comando nosetest seguito dal nome del file, ad es.:
nosetests prova.py

A questo punto dovreste scoprire che il test e' miseramente fallito!
Il motivo di questo non sta nella funzione bensi' nel test, che e' scritto male... Infatti come ci dice l'output si aspettava che il fattoriale di 4 fosse 25 (non 24 come si puo' ottenere moltiplicando i numeri interi da uno a quattro e come giustamente sostiene la funzione scritta).

Correggiamo la tupla di controllo, sostituendo 25 con 24 e rilanciamo il test. Questa volta tutto dovrebbe filare liscio.

Aggiungiamo test meno banali
Come avete visto la funziona supera brillantemente il test. Pero' fallira' quest'altro test:
def test_tipo():
"""Controlla che la funzione fattoriale ritorni un numero di tipo long
"""
for i in (0,1,2,10,200):
assert type(fattoriale(i)) == long ,\
"Il fattoriale di %s non e' di tipo long!" % i

Questo potrebbe rappresentare un problema in certi casi!
Per far passare alla funzione il test occorre modificarla in questo modo:
#!/usr/bin/env python
def fattoriale(n):
"""Funzione ricorsiva per il calcolo del fattoriale di un mnumero
"""
if n == 0:
return 1L
else:
return fattoriale(n-1)*n

Come vedete nel caso n sia 0 ritorna 1L, (prima ritornava semplicemente 1) ovvero un intero di tipo long. Questo forzera' il tipo del risultato ritornato dalle altre iterazioni, facendoci passare il test!

Fattoriale di un numero molto alto
La nostra funzione non e' ancora a prova di bomba. Facciamola scoppiare!
def test_boom():
"""Controlliamo che la funzione reagisca bene quando si trova a che fare
con numeri grandi
"""
fattoriale(1e10)
Per fare in modo che la funzione gestisca questo test occorrera' gestire l'eccezione che viene sollevata nel caso in cui il numero di cui si vuole calcolare il fattoriale sia troppo alto.

Configurare il weather plasmoid

KDE 4 introduce un plasmoide che vi tiene aggiornati sulla situazione meteo della vostra citta'
Ecco come configurarlo in modo rapido e indolore!
  1. Muovete il puntatore del mouse sul widget: apparira' una estensione che mostra alcune icone. Cercate quella per la configurazione (una chiave inglese) e cliccatela.
  2. Vi troverete di fronte ad una finestra di configurazione in cui il primo campo e' lo Zip Code della citta' che vi interessa. Per scoprire quale Zip Code corrisponde alla vostra citta' andate su Yahoo Weather e cercate la vostra citta'. Una volta che l'avrete trovata dovreste essere reindirizzati alla pagina che mostra le informazioni meteo relative. L'indirizzo di questa pagina contiene lo Zip Code. Nel caso della mia citta', Ferrara, questo indirizzo e':
    http://weather.yahoo.com/Ferrara-Italy/ITXX0027/forecast.html
    e lo Zip Code e' ITXX0027.
  3. Copiate l'indirizzo nell'apposito campo
  4. Eventualmente modificate le unita' di misura passando da gradi Fahrenheit a Celsius. 5 minuti come frequenza di aggiornamento e' un valore piu' che ragionevole.
  5. Cliccate il pulsante Ok
Potete aggiungere tutte le weather widget che volete, ciascuna configurata per una citta' diversa (ad esempio per tenere sotto controllo il meteo nella destinazione del vostro prossimo viaggio).

I giornali, l'LHC e la cultura scientifica in Italia

LHC e zero assoluto
A me dispiace che ci caschi sempre di mezzo lui, ma ancora una volta il Corriere della Sera se ne esce con un errore madornale in un articolo a proposito dell'acceleratore di particelle LHC, recente protagonista delle prime pagine dei giornali.

In questo articolo non vi parlero' di buchi neri o di fine del mondo, ma di qualcosa che forse e' ben peggiore: questo articolo!
Parlando della procedura di riparazione, il "giornalista" dice:
l'acceleratore dovrà essere portato a temperature superiori allo zero assoluto.
Alle scuole superiori lo insegnano ancora che la fisica, come la conosciamo oggi, vieta di scendere sotto lo zero assoluto, limite inferiore che non si puo' raggiungere?
Non credo di poter dire che questa sia una svista dell'autore, ma proprio una lacuna sull'argomento. Molto grave a mio parere.

D'altra parte poco prima sempre lo stesso giornalista si avventura in un mondo non suo parlando di "elio superraffreddante": non mi risulta che il termine superraffreddante sia codificato dalla scienza ufficiale.

E' veramente triste constatare che la scienza in Italia sia raccontata in questo modo su una delle maggiori testate giornalistiche. La scienza finisce in prima pagina solo quando assume i connotati stregoneschi di chi puo' distruggere il mondo (vedi LHC e buchi neri) o quando sembra fornire la bacchetta magica (l'energia nucleare toccasana del paese).

Purtroppo la scienza e' altra cosa
Inutile ribadire concetti che alle persone normali sono ben chiari, ma lo faccio lo stesso :)
Un paese senza materie prime deve puntare sulla conoscenza per alimentare il fuoco del progresso, piuttosto che puntare sull'ignoranza, che alimenta solo i politici.
E se i mezzi di comunicazione di massa continueranno cosi', ben difficilmente i giovani si appassioneranno alle meraviglie della natura e al loro studio.

La politica e' anche incentivare la cultura scientifica
Anche di questo si dovrebbe occupare la politica, incentivare un giornalismo scientifico di eccellenza, lasciandogli spazi importanti nei telegiornali delle reti nazionali. Purtroppo gli stessi spazi servono a fare i loro interessi, quindi non lo faranno mai.
A noi, dunque la responsabilita' di colmare questa lacuna, di crescere i nostri figli e di cambiare questa classe politica parassita.

Come aggiungere un link "Continua..." ad un articolo

Vi sara' sicuramente capitato di vedere su vari siti o blog che nella pagina iniziale gli articoli sono visualizzati solo parzialmente e per accedere all'articolo completo dovete cliccare un link del tipo "Read more ...", "Full text ...", "Continua ...", "Leggi l'articolo completo ...", o simili.

Implementare una simile caratteristica per blogspot e' molto piu' semplice di quel che sembra.

Seguite i seguenti passi

  1. Entrate nella bacheca di blogger
  2. Cliccate su "Layout"
  3. Cliccate su "Modifica HTML"
  4. Cliccate su "Scarica modello completo"
  5. Il browser vi chiedera' di salvare un file XML da qualche parte sul vostro pc
  6. Prendete quel file e fatene una copia (utile in caso qualcosa dovesse andare storto)
  7. Aprite la copia del file con un editor di testo (blocco note, note pad o quello che vi pare. Io uso kate)
  8. Cercate il seguente testo: <p><data:post.body/></p>
  9. Sostituitelo con il seguente blocco di codice:
    <b:if cond='data:blog.pageType == "item"'>
    <style>.fullpost{display:inline;}</style>
    <p><data:post.body/></p>
    <b:else/>
    <style>.fullpost{display:none;}</style>
    <p><data:post.body/></p>
    <b:if cond='data:blog.pageType != "item"'>
    <br />
    <b><a expr:href='data:post.url'>Leggi l'articolo completo</a></b>
    </b:if>
    </b:if>
  10. Salvate il file e caricatelo sul sito (dove precedentemente lo avevate scaricato)
  11. Nella pagina web di gestione cliccate "Impostazioni"
  12. Cliccate formattazione
  13. Scrivete nel campo "Modello post" il seguente testo:
    Introduzione

    <span class="fulltext">
    Resto dell'articolo
    </span>
  14. Cliccate su "Salva impostazioni"
Fatto questo dovreste essere a posto

Il prossimo post che creerete vi presentera' il testo di esempio appena inserito.
Al posto di "Introduzione" scrivete il testo che vorrete si veda nella pagina introduttiva, al posto di "Resto dell'articolo" la parte rimanente.

Se qualcosa dovesse andar male ricaricate il file originale, di cui avete fatto una copia al punto 6)