Category Archives: Python

Backup solo se… adesso con Python – 2

Continuo da qui.

n3

click

E finisco per adesso. Nel senso che la versione da terminale è a posto, funziona (pare). Quando tornerà il mio giovane aiutante –anzi committente– G. attualmente in vacanza con i nonni e senza PC vedrò se lo soddisfa. Restano anche da fare: 1) la verifica su Windows (in settimana, probabilmente); e 2) montare un’interfaccia grafica (prossimamente, forse).

tag

Copia in una directory scelta i file elencati nel file di configurazione tag-orig che si trova nella stessa directory del programma. Una copia di questo file di configurazione lo trovate nel post sopraindicato.

Può essere lanciato in due modi, come dallo screenshot qui sotto.

#!/usr/bin/python3

import sys, os.path, shutil

def getorig():
    progname = sys.argv[0]
    progdir = os.path.dirname(progname)
    fbk = os.path.join(progdir, "tag-orig")
    inpf = open(fbk, "r")
    txt = inpf.readlines()
    inpf.close()
    ele = []
    for st in txt:
        sst = st.strip()
        if len(sst) > 0:
            sst = os.path.expanduser(sst)
            fn = os.path.abspath(
                os.path.join(progdir, sst))
            ele.append(fn)
    return ele

def getbkdir():
    if len(sys.argv) > 1:
        dest = os.path.abspath(sys.argv[1])
        if not os.path.isdir(dest):
            dest = ''
    else:
        dest = os.getcwd()

    return dest    

ORIG = getorig()
BKDIR = getbkdir()

if len(BKDIR) == 0:
    print('***', BKDIR, 'non esiste')
    sys.exit(1)

for fn in ORIG:
    print(fn)
    if os.path.isfile(fn):
        sz = os.path.getsize(fn)
        dest = os.path.join(BKDIR, os.path.basename(fn))
        if sz > 7:
            print("\tcopio", fn, "in", dest)
            shutil.copyfile(fn, dest)

tag
agpa
è quello raccontato qui.
OK, forse serve un piccolissimo manuale:

tag [dest]

se dest è una directory (di solito su un drive USB) copia i file elencati nel file di configurazione tag-orig presente nella stessa directory dello script in dest, se non presente la directory di destinazine è quella corrente (quella di $PWD).

r-tag

Copia i file precedentemente salvati con tag nelle loro posizioni originai. Non sovrascrive i file vecchi ma li rinomina aggiungendo a ognuno il suffisso “-old“.

#!/usr/bin/python3

import sys, os.path, shutil

def getorig():
    progname = sys.argv[0]
    progdir = os.path.dirname(progname)
    fbk = os.path.join(progdir, "tag-orig")
    inpf = open(fbk, "r")
    txt = inpf.readlines()
    inpf.close()
    ele = []
    for st in txt:
        sst = st.strip()
        if len(sst) > 0:
            sst = os.path.expanduser(sst)
            fn = os.path.abspath(
                os.path.join(progdir, sst))
            ele.append(fn)
    return ele

def getbkdir():
    if len(sys.argv) > 1:
        bkdir = os.path.abspath(sys.argv[1])
        if not os.path.isdir(bkdir):
            bkdir = ''
    else:
        bkdir = os.getcwd()

    return bkdir    

ORIG = getorig()
BKDIR = getbkdir()

if len(BKDIR) == 0:
    print('***', BKDIR, 'non esiste')
    sys.exit(1)

for fn in ORIG:
    print(fn)
    bkfile = os.path.join(BKDIR, os.path.basename(fn))
    if os.path.isfile(fn):
         shutil.copyfile(fn, fn + '-old')
    if os.path.isfile(bkfile):
        print("\tcopio", bkfile, "in", fn)
        shutil.copyfile(bkfile, fn)

Non metto l’immagine dello screenshot, è molto simile alla precedente e ugualmente incomprensibile.

Manuale minimo:

r-tag [bkdir]

copia i file di back-up presenti nella directory corrente o quella specificata con il parametro bkdir nelle loro posizioni originali, come definite dal file tag-orig. I file vecchi vengono rinominati aggiungendo il suffisso "-old".

a-tag

Accoda ai file indicati nel file di configurazione tag-orig le aggiunte con lo steso nome ma con il prefisso “a-“.

#!/usr/bin/python3

import sys, os.path, shutil

def getorig():
    progname = sys.argv[0]
    progdir = os.path.dirname(progname)
    fbk = os.path.join(progdir, "tag-orig")
    inpf = open(fbk, "r")
    txt = inpf.readlines()
    inpf.close()
    ele = []
    for st in txt:
        sst = st.strip()
        if len(sst) > 0:
            sst = os.path.expanduser(sst)
            fn = os.path.abspath(
                os.path.join(progdir, sst))
            ele.append(fn)
    return ele

def getbkdir():
    if len(sys.argv) > 1:
        bkdir = os.path.abspath(sys.argv[1])
        if not os.path.isdir(bkdir):
            bkdir = ''
    else:
        bkdir = os.getcwd()

    return bkdir    

ORIG = getorig()
BKDIR = getbkdir()

if len(BKDIR) == 0:
    print('***', BKDIR, 'non esiste')
    sys.exit(1)

for fn in ORIG:
    print(fn)
    aggfile = os.path.join(BKDIR, 'a-' + os.path.basename(fn))
    if os.path.isfile(aggfile):
        print("\taggiungo", aggfile, "a", fn)
        f = open(aggfile, 'r')
        agg = f.read()
        f.close()
        f = open(fn, 'a')
        f.write(agg)
        f.close()

Manuale:

a-tag [aggdir]

accoda ai file inidcati nel file di configurazione tag-orig i file con lo stesso nome ma con prefisso "a-" presenti nella directory aggdir; se aggdir non è specificata viene assunta quella corrente.

Non so voi ma nello scrivere questo post mi si sono sviluppati i brufoli :mrgreen:

Backup solo se… adesso con Python – 1

n2
Continuo da qui. Ma cambio tutto. Con bash, shell di Linux, usata negli script dei post precedenti abbiamo visto che non è facilissimo. O meglio, non è come siamo abituati. E poi c’è un grosso limite: non funziona con Windows.
E se provassimo a usare Python?
Sì è un’idea, traduciamo l’ultima versione dello script. Una cosa: da parecchio ormai di Python ne esistono due versioni: la 2.x che continua a essere usatissima per lo più per inerzia e la 3.x, ormai giunta a 3.4; userò questa. Peraltro le differenze (per quello che dobbiamo fare) sono minime.

Ecco la versione iniziale dello script:

#!/usr/bin/python3

import os.path, shutil

ORIG = ["./orig-1/f-1",
        "./orig-1/f-2-piccolo",
        "./orig-2/f1-3",
        "./orig-3/f1 4",
        "./orig-3/f2-4 manca"
       ]

DEST = "./dest/"

for fn in ORIG:
    print(fn)
    if os.path.isfile(fn):
        sz = os.path.getsize(fn)
        dest = DEST + os.path.basename(fn)
        if sz > 7:
            print("\tcopio", fn, "in", dest)
            shutil.copyfile(fn, dest)

t1

OK. L’unica modifica da apportare per utilizzare la versione 2 di Python è di togliere le parentesi a print() che in 2.x è un’istruzione e in 3.x una funzione.

ORIG è adesso una lista (righe 5-10), i componenti sono stringhe. DEST è invece una stringa.

In pratica questo script non è facilmente usabile: i file da copiare sono codificati all’interno dello stesso script, idem la directory di destinazione e resta da vedere cosa capita con nomi più generici.
L’elenco dei file da back-up-pare propongo di memorizzarlo in un file ad hoc, chiamato tag-orig, così:

./orig-1/f-1
./orig-1/f-2-piccolo

~/lab/OKp/lug/Tag-3/orig-2/f1-3
/home/juhan/lab/OKp/lug/Tag-3/orig-2/f1 4

./orig-3/f2-4 manca

Notare che i nomi dei file possono essere relativi alla directory dello script (i primi 2), con l’uso della ~ per indicare la home (il terzo) e assoluti (il quarto). Inoltre ci possono essere righe vuote. Anzi se uno è pasticcione può scrivere commenti: la riga relativa non sarà un file esistente e verrà ignorata.

Ecco lo script per gestirlo:

#!/usr/bin/python3

import os.path, sys

progname = sys.argv[0]
print(sys.argv, progname)
progdir = os.path.dirname(progname)
print(progdir)
fbk = os.path.join(progdir, "tag-orig")
print("file bk =", fbk)
inpf = open(fbk, "r")
ORIG = inpf.readlines()
inpf.close()
print(len(ORIG), ORIG)
print("\n")

for st in ORIG:
    sst = st.strip()
    if len(sst) > 0:
        sst = os.path.expanduser(sst)
        fn = os.path.abspath(
            os.path.join(progdir, sst))
        print(fn)

t12

La path del programma si trova in sys.argv[0], il percorso del file tag-orig viene ricavato usando join() del modulo os.path. di questo modulo utilizziamo anche abspath() ed expanduser(). Quest’ultima si rende necessaria per risolvere ~. Non sono ancora riuscito a provarlo con Windows (G il mio valido aiutante è in vacanza con i nonni e si vede che ha di meglio da fare, beato lui!) ma dovrebbe funzionare (riferirò in futuro).

La directory di destinazione DEST invece dev’essere gestita in modo diverso, secondo me. Propongo due alternative:

  • la directory corrente, quella che con Linux otteniamo con il comando pwd e con Windows con cd;
  • la directory che passiamo allo script come primo argomento; da racchiudere tra apici se contine spazi.

Ritengo che il primo modo sia quello più pratico, pensando a drive (penne) USB, ma chissà…

#!/usr/bin/python3

import os, sys

if len(sys.argv) > 1:
    DEST = os.path.abspath(sys.argv[1])
else:
    DEST = os.getcwd()

print(DEST)

qui

Non resta che inserire questi due pezzi nello script iniziale. Argomento della prossima puntata che se faccio tutto adesso poi di cosa vi racconto? :wink:

Bailey-Borwein-Plouffe

wormsmalltNon ho ancora finito, anzi sarà una storia lunga, ma ho trovato serendipicamente un esercizio, un test per vedere se ho capito qualcosa finora.
La scintilla è stato questo tweet: A shocking formula to calculate any digit of Pi
Sembra fattibile, così a prima vista.

bbpPer sicurezza provo con un linguaggio sensato, Python:

#!/usr/bin/python
# -*- coding: utf-8 -*-

piprec = 3.0 # valore sensato, secondo me ;-)

pi = 0.0
for k in range(10):
    pi += 1. / 16 ** k * (4. / (8 * k + 1) - 2. / (8 * k + 4) -
                          1. / (8 * k + 5) - 1. / (8 * k + 6))
    dpi = pi - piprec
    print k, pi, dpi
    piprec = pi

bbp0

OK. Funziona. E adesso mx.

Ecco, non è che sono ancora praticissimo, anzi, ma provo. Comincio a impratichirmi, l’ho già detto che sono niubbo?

bbp1

OK, dimenticato la maiuscola per Print, ma sembra che Sum si possa usare, si può distribuire anche su più linee.

E (forse) si può anche scrivere la funzione in un file, verifico (ts.mx):

r = Sum[
        a + a^2,
        {a, 1, 3}
    ];
Print["il risultato è ", r]

bbp2Forse si può migliorare (ts1.mx):

r = Sum[
        a + a^2,
        {a, 1, 3}
    ];
Print["il risultato è ", r];

bbp3

no, devo ancora impratichirmi ma il calcolo c’è.

Non è nemmeno una soluzione migliore l’uso della pipe:

bbp4

OK, sono pronto, provo, ecco (bbp.mx):

Sum[
    1. / 16 ^ k (
        4. / (8 k + 1) - 2. / (8 k + 4) -
        1. / (8 k + 5) - 1. / (8 k + 6)),
    {k, 0, 9}
]

bbp5

Cool! provo a alzare il limite superiore della sommatoria, 100 invece di 9:

bbp6

Ho provato a variare il limite, per la mia configurazione questo è 12

 k     pi
 9 - 3.14159265358979115
10 - 3.14159265358979313
11 - 3.14159265358979323
12 - 3.14159265358979324

Poi non varia più. Da qualche parte c’è scritto come aumentare la precisione ma sono ancora troppo niubbo.

Ancora una cosa, risultato di una telefonata non su questo argomento bensì sui linguaggi di programmazione. Ce ne sono tanti, e ne vengono proposti di nuovi continuamente. Si usa quello che fa al caso nostro, anche in funzione dei propri gusti e preferenze; per esempio io sono affezionato a calc:

bbp7Si possono fare degli script con una sintassi C-like, ecco la versione calc di bbp.

#!/usr/bin/calc -f

/* bbp.cal - Bailey-Borwein-Plouffe formula */

piprec = 3.0;
pi = 0.0;
for (k = 0; k < 11; k++) {
	pi = pi + 1. / 16 ** k * (4. / (8 * k + 1) - 2. / (8 * k + 4) -
			       			  1. / (8 * k + 5) - 1. / (8 * k + 6));
	dpi = pi - piprec;
	print k, pi, dpi;
	piprec = pi;
}

bbp8

Domanda: Perché calc?
Risposta: Perché no? :shock:

Ah, sì! Sembra che mx (Mathics) funzioni :cool:

Un quiz di Annarita

Header

Vi voglio raccontare di una mia disavventura programmatica multipla. Però non dovete ridere troppo di me, anche perché comunque c’è l’happy end finale.

Sto studiando mx, ahemmm Mathics e quando ho visto il post della prof. Annarita Ruberto: Trova Il Numero Misterioso mi son detto: “ecco l’occasione per testare la mia conoscenza di mx!“. Disastro, devo ancora impratichirmi, parecchio.

Ma, quando il gioco etc… perché non provare con Python? OK, disastro anche qui.
Perché non avevo capito il senso del testo. E cominciavo a disperarmi. Anzi panico proprio. Non sono più quello di una volta! OK, basta frasi fatte e commiserazioni. Ieri Annarita ha pubblicato (con un giorno di ritardo su quanto aveva minacciato) la soluzione, spiegando i passaggi in modo che capissi anch’io (sigh!): Trova Il Numero Misterioso: La Soluzione E Altre Curiosità.

Insomma questo è il problema:

1. la somma delle cifre di x è un numero y, che, moltiplicato per il numero ottenuto invertendo le sue cifre, dà come prodotto x.
2. Trovando i fattori primi del numero ottenuto invertendo le cifre di x, poi calcolando la semisomma dei quadrati di questi fattori primi, e, infine, rimuovendo la cifra 0 dal nuovo numero, si otterrà il numero x.

E questa la soluzione:

Il numero 1729 soddisfa la condizione 1 del puzzle perché:
la somma delle sue cifre è 19 e 19 ∙ 91 = 1729.
1729 soddisfa anche la condizione 2 perché:
9271 = 73 ∙ 127
e
(73^2 + 127^2) / 2 = 10729. Rimuovendo lo zero da questo numero, si ottiene proprio 1729.

Ah! ma allora, presto, anzi prima di subito, con Python e in futuro (forse) con mx Mathics!

numbers
Solo un paio di osservazioni prima del listato:

  • C’è bisogno di trovare i fattori di un numero, ho trovato una soluzione che mi piace sul solito Stack Overflow: Prime factorization – list. Non l’ho analizzata, funziona, forse in futuro… L’autore ha un blog interessante, su argomenti affini, avendo tempo…;
  • Visto che continuavo a ripetere sempre le stesse istruzioni ho deciso di trasformarle in funzioni, anche quando sono cortissime. Tutto in previsione della futura versione mx (davvero conto di farla, non subito, devo impratichirmi);
  • Queste funzioni sono lispiche, potrebbero essere chiamate in sequenza come usano i funzionali; non l’ho fatto per tenere il codice leggibile (e inserire una marea di print in fase di debug);
  • Inoltre mi sono convertito alla setta degli utilizzatori della list comprehension: è leggibile, comoda, si risparmia una riga. Peggio per quei linguaggi che non ce l’hanno;
  • Per adesso è un abbozzo ma queste funzioni le ho raggruppate in un file che forse evolverà in modulo come si deve.

OK, ecco il codice, addirittura commentato, cosa rara per me.

Il modulo con le funzioni utilizzate:

# -*- coding: utf-8 -*-

# jutils: qui dentro ci metto le funzioni che mi trovo
#         a ricopiare sovente; chissà se funziona

def strlist(st):
    ''' ritorna la lista dei caratteri della stringa st'''
    return list(st)

def ls2str(ls):
    ''' ritorna la stinga unione della lista ls'''
    st = ''
    return st.join(ls)

def lsstr2dig(ls):
    ''' ritorna le cifre della stringa ls'''
    return [int(c) for c in ls]

def strpopc(st, c):
    ''' se la stringa st contiene il carattere
        c questo viene eliminato; una volta sola
    '''
    p = st.find(c)
    if p >= 0:
        st = st[:p] + st[p+1:]
    return st

def factors(n):
    ''' copiato da qui:
        http://stackoverflow.com/questions/ +++
             16996217/prime-factorization-list
    '''
    gaps = [1, 2, 2, 4, 2, 4, 2, 4, 6, 2, 6]
    length, cycle = 11, 3
    f, fs, next = 2, [], 0
    while f * f <= n:
        while n % f == 0:
            fs.append(f)
            n /= f
        f += gaps[next]
        next += 1
        if next == length:
            next = cycle
    if n > 1: fs.append(n)
    return fs

Lo script:

#!/usr/bin/python
# -*- coding: utf-8 -*-

from jutils import *

def passo_1(numero):
    ls = strlist(str(numero)) # lista di caratteri
    n = lsstr2dig(ls)         # lista di cifre
    somma = sum(n)            # somma delle cifre
    ls = strlist(str(somma)) # idem per la somma
    ls.reverse()
    rst = ls2str(ls)
    r = int(rst)              # e quindi in numero
    return (somma * r) == numero

def passo_2(numero):
    ls = strlist(str(numero)) # lista di caratteri
    ls.reverse()              # inverto
    rinv = ls2str(ls)         # trasformo la lista in stringa
    ninv = int(rinv)          # questo è il numero inverso
    fattori = factors(ninv)
    lquad = [i**2 for i in fattori] # lista dei quadrati dei fattori
    nquad = sum(lquad) / 2
    strquad = str(nquad)
    strquad = strpopc(strquad, '0')
    cont = int(strquad)
    return cont == numero

#main
trovato = False
numero = 999
numerofinale = 9999
while not trovato:
    numero += 1
    ok1 = passo_1(numero)
    if numero == numerofinale:
        print "Mi arrendo"
        exit()
    if ok1:
        trovato = passo_2(numero)
        if trovato:
            print "Trovato!", numero

arquiz

Ancora PI, poi basta per un po’

AthenaPeiraeusStampAllora … ultima puntata (per ora, ci sarebbe altro materiale ma non vorrei sembrare monomaniaco) sulle cifre di π, o PI, o pi, o –lui insomma.

Questa volta ricavato e memorizzato su file formattato usando sympy.
Non ci sono arrivato da solo anche perché c’è Stack Overflow. A volte mi chiedo come facevo una volta prima del Web! OK, <mode nostalgia OFF>. Trovato qui: 1000 digits of pi in python, in particolare la risposta di Garret Hyde. Che cita Python Adventures, lo stesso post di cui parlavo la volta scorsa (il mondo è piccolo, anzi no, è enorme ma se ti riesci a orientare :wink:)
Ecco il codice:

#!/usr/bin/python
# -*- coding: utf-8 -*-

def riga_numeri(bl, n):
    f.write(bl + ' ')
    for c in range(n / 5):
        f.write('{:>5} '.format((c + 1) * 5))
    f.write('\n')

def num_col(n):
    f.write('{:>8} '.format(n))

from sympy.mpmath import mp

mp.dps = 1000001  # number of digits
PI = mp.pi
# print(PI)	  # print pi

lunriga = 100 #per TR

f = open("pag-sy", "w")
bl = " " * 8
riga_numeri(bl, lunriga)
n = 0
st = str(PI)

for c in st[2:]:
    if (n % lunriga) == 0:
        num_col(n)
    f.write(c)
    n += 1
    if (n % lunriga) == 0:
        f.write("\n")
    elif (n % 5) == 0:
        f.write(" ")
f.write("\n")
f.close()

pi1Msy

Undici minuti sul mio ‘puter non recentissimo, anzi… Al solito utilizza pienamente una delle CPU presenti:

cpu

E, ovviamente, produce lo stesso risultato di pi, componente della libreria CLN, utilizzato qui: Contare le cifre di PI.

diff

Ops! diff mi dice che c’è un newline di differenza, verificabile anche con ls:

ls

A qualcuno interessa un file di 1.3 MB, abbondante, questo:

dump

Dai con la prossima settimana si cambia argomento :roll:

Tanti decimali, il caso di PI

1986_stamp_83d40m_Athena_Recentemente Ok, panico ha partecipato al Carnevale della Matematica tenuto dall’ottimo GLF :-)
Uno scoop: il carnevale porta pochissime visite, appena visibili se si vanno a cercare ma devi metterci molta cura. Forse perché l’argomento era difficile, troppo teorico? Ma io ho partecipato anche con l’altro blog, quello più generalista, il Tamburo Riparato. Di là era per pubblicizzare Linux, risultati molto scarsi, un flop.
Ma l’argomento m’interessa, anzi lo script originale lo rivelo solo oggi.
E non finisce qui: ho altra roba già in bozza, mica posso buttarla :roll:

Ecco la versione naïf per calcolare PI con tante cifre decimali quanto volete. Usa sympy e non è ottimale, anzi: è lentissimissima:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys, sympy

ndec = int(sys.argv[1]) + 2
# evalf restituisce il numero di cifre,
#compreso il 3 e il punto  iniziale

pi_str = str(sympy.pi.evalf(ndec))
print pi_str

pisym

OK, le ultime cifre non sono attendibili, come si vedrà in seguito. Inoltre è lentissimo; vediamo cosa capita per un caso più sostanzioso, 1 milione di decimali:

pitime

No, non può andare 10 minuti e 32 secondi! Ma quando il gioco si fa :oops: già detto, cancello.

Un sito da prendere in considerazione in questi casi è Rosetta. Sì, c’è il nostro caso, qui.

#!/usr/bin/python
# -*- coding: utf-8 -*-

def calcPi():
    q, r, t, k, n, l = 1, 0, 1, 1, 3, 3
    while True:
        if 4*q+r-t < n*t:
            yield n
            nr = 10*(r-n*t)
            n  = ((10*(3*q+r))//t)-10*n
            q  *= 10
            r  = nr
        else:
            nr = (2*q+r)*l
            nn = (q*(7*k)+2+(r*l))//(t*l)
            q  *= k
            t  *= l
            l  += 2
            k += 1
            n  = nn
            r  = nr

import sys

ndec = int(sys.argv[1]) + 1
pi_digits = calcPi()

i = 0
for d in pi_digits:
    sys.stdout.write(str(d))
    i += 1
    if i == ndec: print; sys.exit(0)

rosetta1

scrive il 3 iniziale, problema minore. Per quanto riguarda la velocità c’è sempre di mezzo il print, per velocizzare si potrebbe mettere in una stringa (problema aggiuntivoo: in Python le stringhe sono immutabili). In ogni caso ecco:

rotime

Niente, l’ho interrotto, dopo 200 minuti. Cosa succede se tolgo l’output commentando la riga 30? Continua a essere molto lento. Mistero, per adesso meglio la mia versione naïf :shock:
Però, che razza di codice! Chissà da dove viene? Ecco, entrano in gioco la Wiki e Google e prima di subito la soluzione:

OK, ma: 1) non è in Python e 2) Haskell? di nuovo?

Beh, Haskell forse in futuro, per Python c’è Laszlo Szathmary: Digits of PI (Part 2).

Non so se l’argomento interessa solo me; in ogni caso conto di parlarne ancora.
Ah! intanto ho scoperto che c’è un clone FOSS di Mathematica, scritto in Python; interessa? a me sì ovviamente.
Prossimamente… forse… :roll:

IPython

While it does not provide any computational or data analytic tools by itself, IPython is designed from the ground up to maximize your productivity in both interactive computing and software development. It encourages an execute-explore workflow instead of the typical edit-compile-run workflow of many other programming languages. It also provides very tight integration with the operating system’s shell and file system. Since much of data analysis coding involves exploration, trial and error, and iteration, IPython will, in almost all cases, help you get the job done faster.

IPy_header

Me ne avevano già parlato in tanti (sul Web) ma l’ho installato solo oggi. E pensare che… OK, ricomincio dall’inizio.

L’ho installato da terminale sudo apt-get install ipython, scarica ben 3MB sull’hard disk ed è pronto:

ip0

Da provare prima di subito:

ip1

OK. Il sito di IPython dice che la versione corrente (stabile) è la 1.2.1 – February 2014. Con Ubuntu viene installata la 0.13.2, anche se si usa sudo apt-get install ipython-notebook come consigliato dalla docmentazione ufficiale (pagina Installing IPython del sito, in realtà installa la versione per il browser) o da Software Center. Chissà se ad aprile, con Trusty Tahr (che sarebbe poi la Fidata Capra dell’Himalaya (pensa te che i francesi non sono ancora riusciti a cambiargli il nome)) si aggiornerà, vedremo.
Anche il manuale in versione PDF non è aggiornato e io ormai li leggo sul Kindle, scollegato.

OK, vediamo:

ip2

Comodo l’autocompletamento!

def f(x, y, z):
    return (x + y) / z

a = 5
b = 6
c = 7.0

result = f(a, b, c)

ip3

Non ci sono ancora arrivato del tutto ma se si ha uno script (t.py nel mio caso) si può valutare (si capisce valutare o è da lisperato perso) con %run. Con %who si ha l’elenco delle variabili, non so se sia possbile modificarle, tipo debug.

Però…
Sto barando. Finora ho copiato. Devo studiare. Io intanto mi leggo il manuale, l’ho appena caricato sul Kindle poi ne riparlo.
Prossimamente :shock: Forse :roll:

Python vs. Perl

Programming-republic-of-perlSono in ritardo su tutto; devo ancora finire due cose per domani ma devo proprio dire una cosa. Anche perché riguarda in qualche misura quello che devo fare per domani.
Perl, devo essere stato uno dei primi a affrontarlo, è nato nel 1987, controllato anche sulla Wiki, non è un errore, credevo prima. No, non ho prove, anche i libri non li ho più. OK, nostalgia mode OFF :shock:

Oggi ho trovato questo post: The Fall Of Perl, The Web’s Most Promising Language.
L’autore, Conor Myhrvold, è –come dire– eclettico. Ma conosce bene la materia il post è informato e esaustivo.

camelMa il motivo vero di queste note è un altro, anzi più di uno.

Python
Oggi le cose in cui Perl eccelleva si fanno con Python; anche le espressioni regolari. E Python ha un grosso vantaggio: la sintassi è molto più amichevole, sembra il Basic di una volta. E anche la storia dell’indentazione (non è che devo dire rientri, vero?) ho visto che è facile da digerire. E Python è molto usato, ci sono librerie (OK, non si chiamano così ma sono quello che una volta si sarebbero chiamate librerie). Metti in conto che non devi compilare e anzi puoi modificare al volo lo script e Python vince alla grande, ad esclusione dei progetti più impegnativi dove si usa Java o il C++. A proposito non so se è una cosa locale ma il C++ ha fama di essere ostico e impegnativo; io trovo tale anche Java, ma chissà :oops:

Octave (Matlab)
Conor dice che Python “even expanding at Matlab’s expense“. Però, per quel che ne so, Matlab è usato parecchio per calcoli di matrici e roba simile; e ha gli stessi vantaggi di scripting di Python. Resta da verificare se serva la versione proprietaria o sia sufficiente Octave, FOSS.

awk
Ci sono però dei casi in cui forse Python ha dei rivali. Per esempio gli script di awk di cui ho parlato nei post precedenti. Funzionano, anzi cresceranno in futuro. Anche se c’è il problema di Windows.

OK, a proposito per domani devo vedere se usare awk (o Perl) o Python. Scelta difficile io sono pythonista convinto ma vengo da sh, sed, awk e Perl.
E una delle cose di cui vado orgoglioso tra quelle recenti è fatta con Gnuplot :roll:

pass in Python

geek

Il post precedente su continue ha generato un commento che mi sembra il caso di sviluppare. Anche perché voglio enunciare esplicitamente una cosa del blog –dei miei post– che è sempre rimasta tra le cose non dette.

Anche se sono fuori dal mondo del lavoro ogni tanto vedo un vecchio (ma molto più giovane di me) amico con cui si parla anche di programmazione. Niente di eccezionale, anzi l’opposto: non si usa il C/C++, troppo complesso o almeno intimidatorio. Per le cose grosse si usa Java, che secondo me è incasinato come il C++ (o quasi). Io ho proposto Go che mi sembra abbordabile ma forse è troppo nuovo. Poi adesso si è iniziato a usare Octave (e forse Matlab) come fanno al Poli. Un linguaggio, anzi tutto un ambiente, il Visual Basic, usatissimo in passato mi sembra un po’ abbandonato, anche perché limitato a Windows. Per le cose normali adesso si usa Python, anche se ci sono cose che ancora non vanno come si vorrebbe. Ma è comodissimo per i piccoli script, mai più di un centinaio di righe. OK, a volte ci sono moduli importati, e poi il numero di righe non conta, vale la bontà dell’algoritmo.

La programmazione è in ogni caso vista come un mezzo, quello che interessa è trovare il risultato di una procedura, di una simulazione. Caso limite ma reale è quello di ottenere un fattore di sicurezza (pare si chiami davvero così) partendo da una massa di dati enorme ed eterogenea. Dove –importante– conta molto più l’operatore che non la macchina e il programma che c’è dentro.
Inoltre un programma (nel nostro caso si dovrebbe parlare di script) è sempre in beta, si modifica al volo quando si rende necessario. E spesso diventa ingestibile, ma questo sarebbe un altro discorso.
C’è un responsabile ma non è detto che sia l’autore dello script. E nessuno legge come dovrebbe i manuali. Anche perché non è necessario sapere tutto e poi manca il tempo.
Le soluzioni eleganti, classi e metodi razionali, come insegnano la scuola e i libri sono spesso sconosciute. Avete presente gli if kilometrici e le variabili globali? OK, se funziona va bene.

Poi, e vengo al dunque, Python ci mette del suo. Come fa notare Roberto nel commento al post citato si potrebbe usare pass:

pass is a null operation — when it is executed, nothing happens. It is useful as a placeholder when a statement is required syntactically, but no code needs to be executed.

Lo script di ieri diventa così:

#!/usr/bin/python
# -*- coding: utf-8 -*-

n = 0
while n < 6:
	n += 1
	c = n % 3
	if c == 0:
		pass
	elif c == 1:
		print n, c, "*"
	else:
		print n, "**"
print "OK!"

pass

Risultato identico a quello dello script di ieri. In realtà l’unica differenza e la sostituzione di continue con pass.

Ci sono differenze tra le due istruzioni? Ho googlato, cercato in Stack Overflow ma non ho trovato niente; forse devo cercare meglio, o forse qualcuno che ne sa di più ci dirà.
Io personalmente ho sempre usato continue (e il suo fratello break) all’interno dei cicli e pass nella gestione delle eccezioni.
A proposito: con gli ing. di cui sopra mai parlare di errori, è una parolaccia :mrgreen:


Poi ogni tanto faccio anche dei post diversi, per esempio ne sto preparando uno che…
prossimamente :cool:

Aggiornamento

al3hex nel commento ha risolto il mistero. Che mistero non era ovviamente :roll:

continue in Python

Una storiella ma forse può essere utile per qualcuno. Questa è capitata per via della standardizzazione: “d’ora in poi tutto in Python (e Java e Octave e …)“. Inoltre a peggiorare le cose c’era il capo che continuava a girare nei paraggi, in questi casi sapete come ci si deve comportare, vero?

geek

Il codice era più complesso, questo è solo un esempio semplificato al massimo.

#!/usr/bin/python
# -*- coding: utf-8 -*-

n = 0
while n < 6:
	n += 1
	c = n % 3
	if c == 0:
		print n, "###"
	elif c == 1:
		print n, c, "*"
	else:
		print n, "**"
print "OK!"

0

In Python non esiste l’istruzione switch o case o cond, solo l’if. Quindi l’esempio è corretto, e funziona.

Però salta fuori che bisogna fare una modifica: nel caso in cui c vale 0 non bisogna far nulla.
Il geek ha modificato il codice così (prudentemente ha commentato anziché cancellare l’istruzione divenuta inutile):

#!/usr/bin/python
# -*- coding: utf-8 -*-

n = 0
while n < 6:
	n += 1
	c = n % 3
	if c == 0:
		#print n, "###"
	elif c == 1:
		print n, c, "*"
	else:
		print n, "**"
print "OK!"

1

Ops! non funziona, Python vuole qualcosa da fare, anche quando vogliamo non faccia nulla.

C’era il capo che girava e allora ecco la soluzione:

#!/usr/bin/python
# -*- coding: utf-8 -*-

n = 0
while n < 6:
	n += 1
	c = n % 3
	if c == 0:
		#print n, "###"
		k = 1
	elif c == 1:
		print n, c, "*"
	else:
		print n, "**"
print "OK!"

2

Sì, inserire un’istruzione qualunque dove Python la vuole, funziona, il capo queste cose non le guarda, caso risolto.

Però, secondo me, non vale. C’è il manuale online, dai, prova a cercare “continue“, c’è in altri linguaggi e fa proprio quello che vogliamo:

continue may only occur syntactically nested in a for or while loop, but not nested in a function or class definition or finally clause within that loop. It continues with the next cycle of the nearest enclosing loop.

Verifica:

#!/usr/bin/python
# -*- coding: utf-8 -*-

n = 0
while n < 6:
	n += 1
	c = n % 3
	if c == 0:
		continue
	elif c == 1:
		print n, c, "*"
	else:
		print n, "**"
print "OK!"

3

OK! Questa può essere intesa come la versione 2014 di “e leggere quel *bip* di manuale!:roll:

Iscriviti

Ricevi al tuo indirizzo email tutti i nuovi post del sito.

Unisciti agli altri 71 follower