[OT] Delphi?? NO! Phyton. Istruzioni per l'uso

Collapse
X
 
  • Filter
  • Ora
  • Show
Clear All
new posts
  • Ribosio80
    Bodyweb Senior
    • Oct 2003
    • 8257
    • 226
    • 51
    • dalle nubi
    • Send PM

    [OT] Delphi?? NO! Phyton. Istruzioni per l'uso

    delphi?? vorrei imparare a programmare bene in delphi....che ne penzate ne vale la pena??




    è attendibile?
    si possono implementare funzioni telnet?
  • Ayurvedi77
    Bodyweb Senior
    • Apr 2002
    • 1632
    • 19
    • 6
    • Pisa
    • Send PM

    #2
    Originariamente Scritto da Ribosio80
    delphi?? vorrei imparare a programmare bene in delphi....che ne penzate ne vale la pena??




    è attendibile?
    si possono implementare funzioni telnet?
    Perchè non dai un'occhio al Python?
    Prima di tutto è multipiattaforma (giacchè interpretato), poi è estremamente potente!
    ___________________


    Codice:
    apt-get remove brain
    apt-get install windows-Vista
    ___________________

    Commenta

    • Nesquik
      Bodyweb Advanced
      • Jan 2003
      • 401
      • 3
      • 0
      • /home/nesquik
      • Send PM

      #3
      Originariamente Scritto da Ayurvedi77
      Perchè non dai un'occhio al Python?
      Prima di tutto è multipiattaforma (giacchè interpretato), poi è estremamente potente!
      quoto in pieno..
      un'alternativa un po' piu' semplice e' il tcl, dotato di molte estensioni, relativamente semplice da imparare, pero', se fosse questo il caso, poco adatto a funzioni di calcolo avendo solamente le stringhe come tipo di dati primitivo.. molto flessibile in ogni caso..
      .
      RFC Project aspetta il tuo contributo

      Originariamente Scritto da JPP
      io non sono umano, io sono l'ex Signore dei Bordelli e trascendo la materia fallace. In me alberga lo spirito di Lord Byron. Rassegnati, a me l'errore è negato

      Commenta

      • Ayurvedi77
        Bodyweb Senior
        • Apr 2002
        • 1632
        • 19
        • 6
        • Pisa
        • Send PM

        #4
        Sai Nesquikko che ero indeciso, poco prima di iniziare a studiare il Python, tra esso ed il Ruby?!
        Quest'ultimo ha una sintassi davvero fantastica!

        Ciò che mi convinse al Python fu il maggiore supporto sul web ed il fatto che si trovava più facilmente qualche IDE...
        ___________________


        Codice:
        apt-get remove brain
        apt-get install windows-Vista
        ___________________

        Commenta

        • Ribosio80
          Bodyweb Senior
          • Oct 2003
          • 8257
          • 226
          • 51
          • dalle nubi
          • Send PM

          #5


          inizio a studiare

          Commenta

          • Ribosio80
            Bodyweb Senior
            • Oct 2003
            • 8257
            • 226
            • 51
            • dalle nubi
            • Send PM

            #6
            probabilmente non avrete piu mie notizie fino al 2007

            Commenta

            • Ribosio80
              Bodyweb Senior
              • Oct 2003
              • 8257
              • 226
              • 51
              • dalle nubi
              • Send PM

              #7
              Python Istantaneo

              di Magnus Lie Hetland
              tradotto da Alex Martelli





              Questo è un corso rapido di minima sul linguaggio di programmazione Python. Per saperne di più, dai un'occhio alla documentazione sul sito web di Python, http://www.python.org/, specialmente il tutorial. Se ti stai chiedendo perchè ti dovrebbe interessare, guarda la pagina dei paragoni, dove Python è paragonato ad altri linguaggi.

              Questa introduzione ha ricevuto molte lodi da lettori soddisfatti, ed è stata tradotta in vari linguaggi, fra cui Portoghese, Russo, Norvegese, Coreano e Spagnolo.

              (Pagina Python di M. L. Hetland)

              1. Fondamenti
              Anzitutto, pensa al Python come pseudo-codice. È quasi vero. Le variabili non hanno tipi, nè si dichiarano. Appaiono quando le assegni, spariscono quando non le usi più. L'assegnazione si fa con l'operatore =. L'eguaglianza si controlla con l'operatore ==. Puoi assegnare più variabili alla volta:

              x,y,z = 1,2,3



              first, second = second, first



              a = b = 123

              I blocchi sono indicati dall'indentazione, e solo dall'indentazione. (Nè BEGIN/END nè graffe.) Alcune comuni strutture di controllo:



              if x < 5 or (x > 10 and x < 20):

              print "Il valore è OK."



              if x < 5 or 10 < x < 20:

              print "Il valore è OK."



              for i in [1,2,3,4,5]:

              print "Iterazione numero", i





              x = 10

              while x >= 0:

              print "x ancora non negativo."

              x = x-1

              I primi due esempi sono equivalenti.

              La variabile indice data nel ciclo for itera sugli elementi di una list (scritta come nell'esempio). Per fare un ciclo for "normale" (cioè un ciclo di conteggio), usa la funzione built-in range().

              # Stampa i valori da 0 a 99 compresi.

              for value in range(100):

              print value

              (La riga che inizia con "#" è un commento, ed è ignorata dall'interprete.)



              Ok; ora ne sai abbastanza per (in teoria) implementare qualsiasi algoritmo in Python. Aggiungiamo un po' di interazione elementare con l'utente. Per avere input dall'utente (da un prompt di testo), usa la funzione built-in input.

              x = input("Immettere un numero: ")

              print "Il quadrato del numero è", x*x

              La funzione input mostra il prompt passatole (che può essere vuoto) e permette all'utente di immettere qualsiasi valore Python valido. In questo caso ci aspettavamo un numero -- se viene immesso qualcosa d'altro (ad esempio una stringa), il programma va in crash. Per evitarlo ci servirebbe un po' di controllo degli errori. Qui non starò a parlarne; basti dire che, se vuoi che l'input dell'utente sia preso verbatim come stringa (così che tutto possa venire immesso), userai invece la funzione raw_input. Se volessi convertire la stringa immessa s in un intero, potresti poi usare int(s).

              Nota: Se vuoi leggere una stringa con input, l'utente dovrà scrivere esplicitamente le virgolette. In Python, le stringhe possono essere racchiuse fra virgolette semplici o doppie.

              Quindi, abbiamo coperto strutture di controllo, input e output -- ora ci servono delle belle strutture dati. Le più importanti sono liste e dizionari. Le liste sono scritte con parentesi quadre, e possono naturalmente essere annidate:

              name = ["Cleese", "John"]



              x = [[1,2,3],[y,z],[[[]]]]

              Una delle cose carine delle liste è che puoi accederne gli elementi separatamente o a gruppi, attraverso indiciamento e affettamento. L'indiciamento si fa (come in molti altri linguaggi) appendendo l'indice fra parentesi quadre alla lista. (Nota che il primo elemento ha indice 0).

              print name[1], name[0] # Stampa "John Cleese"



              name[0] = "Smith"

              L'affettamento è quasi come l'indiciamento, eccetto che scriverai sia l'indice d'inizio sia quello di fine del risultato, con un due-punti (":") a separarli:

              x = ["spam","spam","spam","spam","spam","eggs","and","spam"]



              print x[5:7] # Stampa la lista ["eggs","and"]

              Nota che la fine è non-compresa. Se manca uno degli indici, significa che vuoi tutto in quella direzione. Per esempio list[:3] significa "ogni elemento dall'inizio di list sino all'elemento 3, non compreso" (Si potrebbe sostenere che significa in realtà l'elemento 4, poichè il conteggio parte a 0... vabbè). list[3:], d'altra parte, significherebbe "ogni elemento di list, partendo dall'elemento 3 (compreso) sino all'ultimo, compreso." Per avere risultati davvero interessanti, puoi usare anche numeri negativi: list[-3] è il terzo elemento dalla fine della lista...

              A proposito di indiciamento, potrebbe interessarti sapere che la funzione built-in len ti dà la lunghezza di una lista.

              Ora, dunque -- e i dizionari? Per farla semplice, sono come liste, ma i loro contenuti non sono ordinati. Come si indicizzano allora? Bè, ogni elemento ha una chiave, cioè un "nome" che è usato per trovare l'elemento proprio come in un vero dizionario. Un paio di dizionari d'esempio:

              { "Alice" : 23452532, "Boris" : 252336,

              "Clarice" : 2352525, "Doris" : 23624643}



              person = { 'first name': "Robin", 'last name': "Hood",

              'occupation': "Scoundrel" }

              Ora, per avere l'occupazione di person, usiamo l'espressione person["occupation"]. Se volessimo cambiare il suo cognome, potremmo scrivere:

              person['last name'] = "of Locksley"

              Semplice, no? Come le liste, i dizionari possono contenere altri dizionari. O anche liste. E naturalmente anche le liste possono contenere dizionari. Quindi, si possono facilmente fare strutture dati piuttosto avanzate.

              2. Funzione
              Prossimo passo: l'astrazione. Vogliamo dare un nome a un brano di codice, e chiamarlo con un paio di parametri. In altre parole -- vogliamo definire una funzione (o "procedura"). È facile. Usa la keyword def così:

              def square(x):

              return x*x



              print square(2) # Stampa 4

              Per quelli di voi che lo capiscono: tutti i parametri in Python sono passati per riferimento (come, ad esempio, in Java). Per quelli che non lo capiscono: non ve ne preoccupate

              Python ha gran copia di cose graziose come gli argomenti con nome e gli argomenti di default e può gestire un numero variabile di argomenti a una singola funzione. Per altre informazioni su questo, vedere il tutorial di Python, sezione 4.7.

              Se sai usare le funzioni in generale, questo è quel che ti serve sapere su di loro in Python. (Ah sì... la keyword return termina l'esecuzione della funzione e restituisce il valore datole.)

              Una cosa che potrebbe esserti utile sapere, però, è che in Python le funzioni sono valori. Così, se hai una funzione come square, potresti fare qualcosa come:

              queeble = square

              queeble(2)

              Stampa 4

              Per chiamare una funzione senza argomenti devi ricordarti di scrivere doit() e non doit. Quest'ultimo, come abbiamo mostrato, ritorna solo la funzione stessa, come valore. (Questo vale anche per i metodi degli oggetti... vedi oltre.)

              3. Oggetti e roba...
              Penso tu sappia come funziona la programmazione a oggetti. (Altrimenti, questa sezione potrebbe non avere molto senso per te. Non importa... comincia a giocare senza gli oggetti .) In Python si definiscono le classi con la keyword (sorpresa!) class, così:

              class Basket:



              # Ricorda sempre l'argomento *self*

              def __init__(self,contents=None):

              self.contents = contents or []



              def add(self,element):

              self.contents.append(element)



              def print_me(self):

              result = ""

              for element in self.contents:

              result = result + " " + `element`

              print "Contiene:"+result

              Cose nuove qui:
              1. Tutti i metodi (funzioni di un oggetto) ricevono un argomento in più all'inizio della lista degli argomenti, che contiene l'oggetto stesso (detto self in questo esempio, il che è l'abitudine.)
              2. I metodi si chiamano così: object.method(arg1,arg2).
              3. Alcuni nomi di metodo, come __init__, sono predefiniti, con significati speciali. __init__ è il nome del costruttore della classe, cioè la funzione chiamata quando crei un'istanza.
              4. Alcuni argomenti possono essere opzionali e avere un valore di default (come detto prima, nella sezione sulle funzioni). Questo si fa scrivendo la definizione come: def spam(age=32): ...

                Qui, spam può essere chiamata con uno o zero parametri. Se non ne vengono usati, il parametro age avrà valore 32.
              5. "Logica corto circuito". È un dettaglio carino... vedi sotto.
              6. Gli apostrofi rovesciati convertono un oggetto alla sua rappresentazione stringa. (Così se element contiene il numero 1, allora `element` è lo stesso di "1" mentre 'element' è una stringa letterale.)
              7. Il segno di addizione + è usato anche per concatenare liste e stringhe. Le stringhe in realtà sono solo liste di caratteri (il che significa che potete usare su di esse indiciamento e affettamento e la funzione len. Ganzo, eh?)
              Nessun metodo (nè variabile membro) è protetto (o privato o simile) in Python. L'incapsulamento è praticamente questione di stile di programmazione. (Se ti serve davvero, ci sono convenzioni sui nomi che permettono un po' di privacy ).

              Ora, quella logica corto-circuito...

              Tutti i valori in Python possono essere usati come valori logici. Alcuni dei più "vuoti", come [], 0, "" e None rappresentano la falsità logica, mentre la maggior parte degli altri valori (come [0], 1 o "Hello, world") rappresentano la verità logica.

              Ora, le espressioni logiche come a and b sono valutate così: Primo, si controlla se a è vero. Se non lo è, è il risultato. Se lo è, il risultato è b (che rappresenterà il valore di verità dell'espressione.) La logica corrispondente per a or b è: se a è vero, è il risultato. Se non lo è, il risultato è b.

              Questo meccanismo fa sì che and e or si comportino come gli operatori booleani che dovrebbero implementare, ma ti permette anche di scrivere espressioni condizionali semplici e dolci. Per esempio, l'istruzione

              if a:

              print a

              else:

              print b

              potrebbe essere scritta anche:

              print a or b

              In effetti, questo è piuttosto idiomatico in Pyton, quindi meglio abituarcisi. È quel che facciamo nel metodo Basket.__init__. L'argomento contents ha un valore di default di None (che è, fra le altre cose, false). Quindi, per controllare se ha un valore, potremmo scrivere:

              if contents:

              self.contents = contents

              else:

              self.contents = []

              Naturalmente, ora sai che c'è un modo migliore. E perchè non gli diamo il valore di default di [] da subito? Perchè a causa di come funziona Python, questo darebbe a tutti i Basket la stessa lista vuota come contenuto di default. Appena uno comincia a riempirsi, tutti conterrebbero gli stessi elementi, e il default non sarebbe più vuoto... per imparare di più su questo, dovresti leggere la documentazione e cercare la differenza fra identità e eguaglianza.

              Un altro modo di fare quanto sopra è:

              def __init__(self, contents=[]):

              self.contents = contents[:]

              Puoi indovinare come questo funziona? Invece di usare la stessa lista vuota dappertutto, usiamo l'espressione contents[:] per fare una copia. (Semplicemente, affettiamo il tutto.)

              Così, per fare effettivamente un Basket e usarlo (cioè chiamare qualche metodo su di esso) faremo qualcosa come:

              b = Basket(['apple','orange'])

              b.add("lemon")

              b.print_me()

              Ci sono altri metodi magici oltre a __init__. Uno di essi è __str__, che definisce che aspetto vuole avere l'oggetto se viene trattato come stringa. Potremmo usarlo nel nostro Basket invece di print_me:

              def __str__(self):

              result = ""

              for element in self.contents:

              result = result + " " + `element`

              return "Contains:"+result

              Ora, se volessimo stampare il Basket b, potremmo semplicemente usare:

              print b

              Ganzo, eh?

              Le sottoclassi si fanno così:

              class SpamBasket(Basket):

              # ...

              Python permette eredità multipla, quindi puoi avere varie superclassi fra parentesi, separate da virgole. Le classi si istanziano così: x = Basket(). I costruttori, come dicevo, si fanno definendo la speciale funzione membro __init__. Supponiamo che SpamBasket abbia un costruttore__init__(self,type). Allora potresti farne uno così: y = SpamBasket("apples").

              Se, nel costruttore di SpamBasket, ti servisse chiamare il costruttore di una o più superclassi, potresti chiamarlo così: Basket.__init__(self). Nota che, oltre ai normali parametri, devi fornire esplicitamente self, poichè la __init__ della superclasse non sa con quale istanza stia trattando.

              Per altre meraviglie sulla programmazione a oggetti in Python, vedi la sezione 9 del tutorial.

              4. Un trucco mentale Jedi.
              (Questa sezione è qua solo perchè penso che sia bella. Decisamente non è necessario leggerla per iniziare a imparare Python.)

              Ti piacciono i concetti sbalorditivi? Allora, se sei davvero audace, potresti dare un'occhiata al saggio di Guido van Rossum sulle metaclassi. Se però preferisci che il tuo cervello non esploda, potrebbe bastarti questo trucchetto.



              Python usa spazi di nomi dinamici e non lessicali. Questo significa che se hai una funzione così:

              def orange_juice():

              return x*2

              ... dove una variabile (in questo caso x) non è connessa a un argomento e non riceve un valore entro la funzione, Python userà il valore che essa ha dove e quando la funzione è chiamata. In questo caso:

              x = 3

              y = orange_juice()

              # y è ora 6

              x = 1

              y = orange_juice()

              # y è ora 2

              Di solito, questo è il tipo di comportamento che desideri (benchè questo esempio sia un po' artificioso - raramente si accede così alle variabili.) Tuttavia, a volte può essere carino avere qualcosa di simile a uno spazio di nomi statico, cioè, memorizzare alcuni valori dall'ambiente nella funzione quando viene creata. Il modo di fare questo in Python è attraverso gli argomenti di default.

              x = 4

              def apple_juice(x=x):

              return x*2

              Qui, l'argomento x riceve un valore di default che è eguale al valore della variabile x nel momento in cui la funzione viene definita. Quindi, sinchè nessuno fornisce un argomento per la funzione, si comporterà così:

              x = 3

              y = apple_juice()

              # y is now 8

              x = 1

              y = apple_juice()

              # y is now 8

              Così - il valore di x non è cambiato. Se ci servisse solo questo, avremmo equivalentemente potuto scrivere:

              def tomato_juice():

              x = 4

              return x*2

              o anche

              def carrot_juice():

              return 8

              Tuttavia, il punto è che il valore di x è raccolto dall'ambiente nel momento in cui la funzione viene definita. In che modo questo è utile? Facciamo un esempio -- una funzione che compone altre due funzioni.

              Vogliamo una funzione che lavora così:

              from math import sin, cos



              sincos = compose(sin,cos)



              x = sincos(3)

              Dove compose è la funzione che vogliamo costruire, e x ha il valore -0.836021861538, cioè sin(cos(3)). Ora, come facciamo questo?

              (Nota che qui stiamo usando funzioni come argomento... il che è un trucco già parecchio carino in sè.)

              Chiaramente, compose accetta due funzioni come parametri, e restituisce una funzione che accetta un parametro. Quindi, uno scheletro di soluzione potrebbe essere:

              def compose(fun1, fun2):

              def inner(x):

              pass # ...

              return inner

              Potremmo essere tentati di scrivere return fun1(fun2(x)) entro la funzione inner e accontentarci. No, no, no. Questo si comporterebbe molto stranamente. Immagina il seguente scenario:

              from math import sin, cos



              def fun1(x):

              return x + " world!"



              def fun2(x):

              return "Hello,"



              sincos = compose(sin,cos) # usa la versione sbagliata



              x = sincos(3)

              Ora, che valore avrebbe x? Esatto: "Hello, world". Perchè? Perchè quando compose viene chiamata, raccoglie i valori di fun1 e fun2 dall'ambiente, non quelli che erano in giro quando fu creata. Per avere una soluzione funzionante, tutto quel che dobbiamo fare è usare la tecnica che ho descritto prima:

              def compose(fun1, fun2):

              def inner(x, fun1=fun1, fun2=fun2):

              return fun1(fun2(x))

              return inner

              Ora dobbiamo solo sperare che nessuno passi alla funzione risultante più di un argomento, perchè questo la romperebbe . A proposito, visto che non ci serve il nome inner, ed esso contiene solo un'espressione, tanto vale fare una funzione anonima, usando la keyword lambda:

              def compose(f1, f2):

              return lambda x, f1=f1, f2=f2: f1(f2(x))

              Conciso, ma chiaro. Devi amarlo

              (E se non ne hai capito nulla, non preoccuparti. Almeno spero ti abbia convinto che Python è più che "solo un linguaggio di scripting"... )

              5. E ora...
              Giusto poche cosette vicino alla fine. La maggioranza delle funzioni e classi utili sono piazzate in moduli, che sono file di testo contenenti codice Python. Puoi importarli e usarli nei tuoi programmi. Per esempio, per usare il metodo split del modulo standard string, puoi fare, o:

              import string



              x = string.split(y)

              Oppure...

              from string import split



              x = split(y)

              Per altre informazioni sui moduli della libreria standard, dai un'occhiata a www.python.org/doc/lib. Contengono un mucchio di roba utile.



              Tutto il codice nel modulo/script è eseguito quando viene importato. Se vuoi che il tuo programma possa essere usato sia come modulo importabile sia come programma eseguibile, aggiungi alla fine di esso qualcosa come:

              if __name__ == "__main__": go()

              Questo è un modo magico per dire che se questo modulo viene fatto girare come script eseguibile (cioè, se non stiamo venendo importati da un altri script), allora va chiamata la funzione go. Naturalmente, potresti fare qualsiasi cosa in questa posizione dopo il due-punti...

              E per quelli di voi che vogliono rendere eseguibile uno script su UN*X, usate la seguente prima riga per farlo funzionare da solo:

              #!/usr/bin/env python

              Infine, breve menzione di un concetto importante: le Eccezioni. Alcune operazioni (come dividere per zero, o leggere da un file inesistente) producono una condizione di errore, cioè di eccezione. Puoi anche farti le tue, sollevandole in momenti appropriati.

              Se non viene gestita l'eccezione, il tuo programma termina e stampa un messaggio di errore. Puoi evitarlo con una istruzione di try/except. Per esempio:

              def safe_division(a,b):

              try:

              return a/b

              except ZeroDivisionError:

              return None

              ZeroDivisionError è un'eccezione standard. In questo caso, avresti potuto controllare se b era zero, ma in molti casi, questa strategia non è applicabile. Inoltre, se non avessimo la clausola try in safe_division, cioè se fosse una funzione rischiosa da chiamare, potremmo ancora fare qualcosa come:

              try:

              unsafe_division(a,b)

              except ZeroDivisionError:

              print "Something was divided by zero in unsafe_division"

              Nei casi in cui normalmente non ci sarebbe uno specifico problema, però potrebbe succedere, usare le eccezioni permette di evitare costosi controlli ecc.

              Beh, questo è tutto. Spero tu abbia imparato qualcosa. Ora vai e gioca. E ricorda il motto per imparare il Python: "Use the source, Luke." (Traduzione: leggi tutto il codice su cui puoi mettere le mani ) Per cominciare, ecco un esempio. È il ben noto algoritmo QuickSort di Hoare. Una versione con sintassi colorizzata è qui.

              C'è una cosa che può meritare di essere detta su questo esempio. La variabile done controlla se la partition abbia o meno finito di muovere gli elementi. Quindi, quando uno dei due cicli interni vuol terminare l'intera sequenza di scambi, mette done ad 1, poi esce con break. Perchè i cicli interni usano done? Perchè, quando il primo ciclo interno finisce con break, se il prossimo ciclo debba partire o meno dipende dal fatto che il ciclo principale sia finito, cioè, se done sia stata o meno posta ad 1:

              while not done:

              while not done:

              # Itera sino ad un break



              while not done:

              # Eseguito solo se il primo non ha posto "done" ad 1

              Una versione equivalente, forse più chiara, ma nella mia opinione meno bellina, sarebbe:

              while not done:

              while 1:

              # Itera sino ad un break



              if not done:

              while 1:

              # Eseguito solo se il primo non ha posto "done" ad 1

              L'unica ragione per cui ho usato la variabile done nel primo ciclo era che mi piaceva conservare la simmetria fra i due. Così li si potrebbe scambiare e l'algoritmo funzionerebbe ancora.

              Alcuni altri esempi si trovano sulla pagina dei bocconcini di Joe Strout.

              Commenta

              • Ribosio80
                Bodyweb Senior
                • Oct 2003
                • 8257
                • 226
                • 51
                • dalle nubi
                • Send PM

                #8
                Uno sguardo al Python
                di Michele Sciabarrà



                Java è un linguaggio che è venuto alla ribalta molto di recente, quando i giochi sui linguaggi di programmazione sembravano fatti: chi avrebbe mai immaginato, solo pochi anni fa, che si sarebbe potuto affermare in così breve tempo un nuovo major programming language per il quale sono già disponibili decine con ambienti di svilupp e numerose librerie? Allo stesso modo, Python si è imposto quando sembrava non esserci spazio per nuovi linguaggi di scripting: tra Perl, JavaScript, Tcl/Tk e Scheme non sembrava esserci spazio per altri… In realtà nel mondo informatico ci sarà sempre spazio per l'innovazione, fermo restando il fatto che i vecchi sistemi non spariscono mai del tutto… vedi COBOL e FORTRAN.

                Le similitudini tra Python e Java non finiscono qui: il bello di Java, a parte l'aspetto "politico" di rappresentare una piattaforma alternativa a Windows, è dato dal linguaggio stesso: Java sembra riassumere per certi versi il meglio del C++ e del Visual Basic. Java è moderno, object oriented senza compromessi ed esagerazioni; è più potente del Visual Basic, da cui eredita la capacità di creare intefacce grafiche con semplicità; si presenta ben più semplice del C++, da cui deriva molte potenzialità, espresse però in maniera più semplificata e chiara sia sintatticamente che semanticamente.

                La storia del Python sembra molto simile nell'ambito dei linguaggi di scripting in ambiente Unix. Perl e Tcl/Tk sono stati per anni l'unica opzione; entrambi sono derivati dallo scripting di shell, ed entrambi con pregi e difetti (sintassi e semantica astrusa il Perl, alcune limitazioni di scalabità il Tcl/Tk). Python sembra riassumere per certi versi il meglio del Perl e del Tcl/Tk. Python è moderno, object oriented senza compromessi ed esagerazioni; è più potente del Tcl/Tk, da cui eredita la capacità di creare intefacce grafiche con semplicità; si presenta ben più semplice del Perl, da cui deriva molte potenzialità espresse però in maniera più semplificata e chiara sia sintatticamente e semanticamente. Non è un caso che l'ultima frase sia analoga dalla precedente sostituendo Perl a C++, Tcl/Tk a Visual Basic e Python a Java…

                In effetti la mia esperienza personale con il Python assomiglia molto alla mia esperienza con il Java. Non ho mai voluto usare il Visual Basic, preferendovi per anni il C++, e scontrandomi regolarmente con le sue astrusità, finché ho scoperto Java: la versione più semplice del C++ che offre molto dei vantaggi del Visual Basic… e da allora ho usato quasi esclusivamente Java. Analogamente non ho mai voluto usare il Tcl/Tk, preferendovi per anni il Perl, e scontrandomi regolarmente con le sue astrusità finchè non ho scoperto il Python…




                Primo impatto

                Python è un interprete. Niente di strano trattandosi di un linguaggio di scripting. A differenza di altri però può essere utilizzato interattivamente. Eseguendo python dalla riga di comando (che sia Unix o NT) otteniamo il prompt (in questo caso su NT):




                PythonWin 1.5.1 (#0, Apr 13 1998, 20:22:04) [MSC 32 bit (Intel)] on win32

                Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

                >>>




                Dopo il >>> possiamo digitare dei comandi e quindi eseguire delle semplici operazioni:




                >>> 2+2

                4

                >>> a=5

                >>> a+1

                6

                >>> def sum(a,b): return a+b

                >>> sum(4,5)

                9




                Come si vede, il Python è innanzitutto un valutatore di espressioni, ma consente di assegnare variabili e definire delle funzioni. Fin qui niente di eccezionale. Ora però cominciamo a fare qualcosa un po' più audace.




                >>> __builtins__

                <module '__builtin__'>

                >>> dir(__builtins__)

                ['ArithmeticError', … OMISSIS …

                'abs', 'apply', 'callable', 'chr', 'cmp', 'coerce', 'compile', 'complex', 'delattr', 'dir', 'divmod', 'eval', 'execfile', 'filter', 'float', 'getattr', 'globals', 'hasattr', 'hash', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'len', 'list', 'locals', 'long', 'map', 'max', 'min', 'oct', 'open', 'ord', 'pow', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'round', 'setattr', 'slice', 'str', 'tuple', 'type', 'vars', 'xrange']




                La variabile __builtins__ è di tipo modulo, come dice il messaggio ottenuto dalla sua valutazione; si tratta del modulo che contiene tutti i builtins, ovvero le funzioni predefinite del sistema. Per vedere il contenuto di un modulo (o di un qualsiasi namespace in generale - un modulo è un particolare namespace) posso usare il builtin dir, che in questo caso mi consente di elencare tutti gli altri builtin. I builtin sono funzioni immediatamente disponibili senza particolari operazioni. Continuiamo le nostre esplorazioni, provando ad utilizzare un builtin.




                >>> open

                <built-in function open>

                >>> open("c:\\autoexec.bat")

                <open file 'c:\autoexec.bat', mode 'r' at 870920>

                >>> x=open("c:\\autoexec.bat")

                >>> dir(x)

                ['close', 'closed', 'fileno', 'flush', 'isatty', 'mode', 'name', 'read', 'readinto', 'readline', 'readlines', 'seek', 'softspace', 'tell', 'truncate', 'write', 'writelines']

                >>> x.readline

                <built-in method readline of file object at 8745d0>

                >>> x.readline()

                'rem - By Windows 95 Network - C:\\WINDOWS\\net start\012'




                Vediamo se vi è chiaro quello che ho fatto: open è un builtin; infatti valutando open mi viene comunicato che si tratta di una funzione builtin (un oggetto quindi di tipo diverso dal modulo visto prima); questo oggetto può essere usato invocandolo con un parametro, ovvero il nome di un file: così facendo ottengo un altro oggetto che rappresenta un file aperto. Per utilizzare il file lo salvo in una variabile e provo ad esaminarne il contenuto con dir,scoprendo che l'oggetto contiene al suo interno una serie di funzioni (o più correttamente metodi). Provo ad utilizzare la readline, che è una funzione e non una proprietà e quindi invoco la funzione, senza parametri, ottenendo quello che mi aspetto: la prima riga del file AUTOEXEC.BAT che ho aperto.

                I builtin sono immediatamente disponibili, ma si tratta di un caso particolare: in generale le funzioni è necessario importarle. Come è possibile accedere ai metodi di un oggetto, è anche possibile accedere alle funzioni presenti in un file, o meglio modulo. Per usare le funzioni di un modulo, occorre importarlo. Vediamo subito come si fa, esaminando il modulo per le espessioni regolari (un assoluto must per chi vuole utilizzare il Python come un sostituto per il Perl).




                >>> re

                Traceback (innermost last):

                File "<interactive input>", line 0, in ?

                NameError: re

                >>> import re

                >>> re

                <module 're'>

                >>> match

                Traceback (innermost last):

                File "<interactive input>", line 0, in ?

                NameError: match

                >>> from re import match

                >>> match

                <function match at 850e90>




                Non ci interessa in questa sede il funzionamento del modulo re, per il momento ci limitiamo ad esaminanare il meccanismo di importazione. Inizialmente re non è disponibile, lo diventa dopo che eseguiamo import re. A questo punto possiamo vedere il modulo, ma le funzioni in esso contenute (che in questo caso non sono metodi) sono accessivibili solo con la sintassi puntata: re.match. È però possibile rendere accessibile definitivamente una funzione senza dove specificare il modulo con la sintassi from re import match. Notare che in questo modo viene resa disponibile per l'accesso immediato soltanto una funzione, anche se possono essere importate tutte (ma in generale, a meno di moduli semplici, non è il caso).




                Sequenze e dizionari

                In Python abbiamo tre categorie di tipi di dato. I tipi primitivi (interi e float), gli oggetti e le sequenze. Le sequenze presenti in Python attualmente sono stringhe, liste e tuple. Vediamo innanzitutto le stringhe




                >>> s = 'Hello'

                >>> s = s+', world'

                >>> s

                'Hello, world'

                >>> len(s)

                12

                >>> s[0:5]

                'Hello'

                >>> s[7:]

                'world'

                >>> s[0]

                'H'

                >>> s[-1]

                'd'

                >>> dir(s)

                []

                >>> x='a'

                >>> x=x+'b'

                >>> x

                'ab'




                Le stringhe possono essere espresse con una costante: basta scrivere i caratteri che la compongono tra virgolette, singole o doppie. Le variabili in Python, come ormai dovrebbe essere chiaro, non sono tipizzate e non vanno dichiarate: quindi per creare una variabile contentente una stringa basta assegnare una costante stringa alla variabile. Le stringhe sono immutabili: questo vuol dire che una volta create non possono essere modificate, si può solo creare un'altra stringa. Le stringhe possono essere concatenate utilizzando l'operatore +, come si vede nell'esempio, ma in questo caso vengono buttate via le due stringhe preesistenti, costruendone una nuova risultante dalla concatenazione delle due precedenti. Le stringhe, come tutte le sequenze in genere, sono indicizzabili tramite l'operatore [], che può specificare un range, separato dai due punti: questa operazione viene chiamata slicing.

                Riferiamoci all'esempio di prima. Possiamo notare subito che i range partono da 0 e che il range s[a:b] indica tutti gli elementi da a incluso a b escluso. Usare un numero negativo come indice equivale ad indicizzare a partire dall'ultimo elemento; quando ometto il primo elemento del range si intende 0, quando ometto il secondo si intende il len della sequenza. Un esame della stringhe con dir rivela che non ha metodi: questo significa che una stringa può essere manipolata soltanto utilizzando i builtin e gli operatori predefiniti. Un'altra sequenza immutabile è la tupla:




                >>> x = 1,2,3

                >>> x

                (1, 2, 3)

                >>> a,b,c = x

                >>> a

                1

                >>> b

                2

                >>> c

                3

                >>> x[0:1]

                (1,2)

                >>> x,y = 7,8

                >>> x+y

                15




                Separando con una virgola una serie di elementi si costruisce una tupla, o meglio si impaccano (packing) gli elementi un una tupla. Questa operazione ha il suo constrario nello spacchettamento (unpacking) della tupla, che si ottiene ponendo una serie di variabili a sinistra di un assegnamento. Essendo le tuple sequenze, anche su di esse si può operare con lo slicing, come le stringhe. Python ha dunque l'assegnamento multiplo, che tecnicamente è un packing ed unpacking di tupla. Le tuple sono comode in molti casi, ma sono immutabili come le stringe, e si può operare con esse solo utilizzando poche operazioni, quelle standard per le sequenze, riassunte in Tabella 1. Esiste una struttura dati molto più flessibile, ma ovviamente anche più inefficiente, ovvero la lista:




                >>> x=[1,3]

                >>> x

                [1, 3]

                >>> x.append(4)

                >>> x

                [1, 3, 4]

                >>> x.insert(1,2)

                >>> x

                [1, 2, 3, 4]

                >>> x.reverse()

                >>> x

                [4, 3, 2, 1]

                >>> dir(x)

                ['append', 'count', 'index', 'insert', 'remove', 'reverse', 'sort']




                Tabella 1
                Operazione
                Risultato
                X in S

                Cerca X nella sequenza S

                X not in S

                Inverso del precedente

                S + T

                Concatezione generica di sequeze

                S * N

                Iterazione di S per N volte

                S[i]

                I-simo elemento di S

                S[I:J]

                Slice da I incluso a J escluso.

                len(S)

                Lungheszza della sequenza

                Min(S), Max(S)

                Minino e massimo di S

                A differenza delle tuple, le liste sono mutabili e si possono eseguire più operazioni su di esse. Le liste possono essere create utilizzando l'apposita sintassi, comprendo gli elementi tra parentesi quadre, e su di esse si può operare utilizzando una serie di metodi predefiniti: append, insert, reverse, eccetera, come si può vedere nell'esempio, oltre al solito slicing. Vediamo infine i dizionari, ovvero gli array associativi che sono anche essi tipi primitivi in Python:




                >>> x={'a':1, 'b':2}

                >>> x

                {'b': 2, 'a': 1}

                >>> x['a']

                1

                >>> x['c']=3

                >>> dir(x)

                ['clear', 'copy', 'get', 'has_key', 'items', 'keys', 'update', 'values']

                >>> x.keys()

                ['b', 'c', 'a']

                >>> x.values()

                [2, 3, 1]

                >>> x.items()

                [('b', 2), ('c', 3), ('a', 1)]




                Il funzionamento dovrebbe essere abbastaza ovvio. Le costanti per definire i dizionari sono della forma { key:val, keys:val, … } . Per accedere agli elementi si usa la sintassi per l'indicizzazione di una sequenza; si può assegnare un elemento per crearlo, e si può eliminare un elemento con del. I dizionari non sono sequenze, ma li tratto in questo paragrafo per affinità con le altre strutture dati primitive. Se serve si possono ottenere facilmente le sequenze delle chiavi, dei valori e di tutti gli elementi (una lista di tuple).




                Controllo di flusso

                Python è un linguaggio imperativo e ha quindi il controllo di flusso usuale, con if, while e for. Un aspetto importante e caratteristico del Python è la modalità di "accorpamento" dei comandi, ovvero come si definiscono i blocchi. I linguaggi tradizionali usano le parentesi: le graffe C e Java, begin-end il Pascal ecceter. Il Python usa l'indentazione per raggruppare gli statementi. Vediamo subito un esempio:




                >>> def max(a,b):

                ... if a>b:

                ... return a

                ... else:

                ... return b

                ...

                >>> max(1,2)

                2




                Tabella 2 if <condition>: <block>
                [elif <condition>: <block>]*
                [else: <block>


                Comune If/then/else in Python

                while <condition>: <block>
                [else: <block>]


                Comune While in Python - il blocco in else è eseguito dop la condizione se il ciclo non termina con un break

                for <target> in <condition-list>: <block>
                [else: <block>]


                Itera per ogni elemento della sequenza e lo assegna alla variabile target -il blocco in else è eseguito dopo la condizione se il ciclo non termina con un break

                break

                Termina un ciclo for o while

                continue

                Esegue la successiva iterazione di un ciclo for o while

                return [<result>]

                Ritorna il risultato dalla funzione o metodo corrente - se result è omesso ritorna None

                I comando if, while, for, def sono composti, quindi devono essere seguite da un blocco, che viene separato dalla condizione con due punti. Il blocco comincia dalla riga successiva e finisce in una indentata quanto la corrente o meno. Visivamente si ha quello che ci si aspetta: tutte le linee seguenti ad un comando composto e più indentate di esso appartengono al blocco di quel comando. Oltre alla sintassi già di per sé abbastanza chiara, questa caratteristica è una marcia in più che contribuisce a rendere i sorgenti in Python estremamente leggibili: quella che prima era solo una norma estetica in Python diventa una regola di programmazione. Come dire che un programma è corretto solo se è anche scritto ordinato! Inoltre, l'uso dell'indentazione elimina molti problemi abbastanza frequenti legati al matching delle parentesi. Infine questo contribuisce a rendere la sintassi minimale, quello che si vuole da un linguaggio di scripting comodo e veloce da usare. Gli elementi del controllo di flusso sono riassunti in tabella 2. Esaminiamoli uno ad uno.

                L'if è il consueto blocco condizionale. L'unica particolarità da notare è che, poichè gli if in cascata risulterebbero sconvenienti da scrivere, per esempio:




                >>> if a=1:

                ... …

                ... else:

                ... if a=2:

                ... …

                ... else:

                ... if a=3:

                ... …

                ... else:




                esiste la clausola elif, per cui l'esempio di sopra può essere scritto più semplicemente e chiaramente in Python come:




                >>> if a=1:

                ... …

                ... elif a=2:

                ... …

                ... elif a=3

                ... …

                ... else:

                ... …




                Il ciclo while è simile all'if eccetto che itera il corpo finchè la condizione non è verificata. La particolarità da notare in questo caso è una comoda clausola else che viene eseguita solo quando la condizione diventa falsa. Sono disponibili i comandi break per interrompere il ciclo e continue per continuare il ciclo alla iterazione successiva. Notare che l'else del while (e anche del for che vedremo dopo) non viene eseguito se il ciclo termina con un break. Questo rende agevole scrivere certi cicli in cui si deve distinguere se il ciclo è stato terminato normalmente oppure no. Per esempio, supponiamo di voler cercare una riga in un file per fare dei calcoli, e ritornare il valore speciale None se la riga non è stata trovate nel file. Ecco come si può fare in Python:




                >>> while <ci sono righe nel file>

                ... if <trovata la riga>:

                ... break

                ... else:

                ... return None

                ... <elabora la riga>

                ... return <la riga elaborata>




                Infine il for,che è speciale, nel senso che non è un while compattato come in Java o C. Il for itera su tutti gli elementi di una sequenza:




                >>> for i in 'abc':

                ... print i, "-",

                ...

                a - b - c -

                >>> for i in 1,2,3:

                ... print i*i

                ...

                1

                4

                9




                Per inciso notiamo la print, che prende i suoi argomenti separati da virgole; se l'ultimo argomento è omesso (notare la virgola senza niente dopo) la print non genera un newline, come fa nel secondo caso. Il for può essere usato sulle stringhe, sulle tuple e anche sulle liste. In Python quindi non c'è un modo esplicito per andare da 6 a 12 a passi di 2, ma occorre appoggiarsi alla funzione range(<inizio>, <fine> [,<passo>]) che costruisce una lista con gli elementi necessari. Quindi questo è il modo corretto per andare da 6 a 12 a passi di due:




                >>> for i in range(6,13,2):

                ... print i,

                ...

                6 8 10 12




                Notare che abbiamo usato 13 perchè in un range il limite superiore (12) è escluso.

                Python supporta la programmazione ad oggetti in maniera consistente ed elegante, ed ha una libreria di classi piuttosto ampia che copre molte necessità. La dichiarazione delle classi in Python è piuttosto complessa, per cui per motivi di spazio non approfondiremo qui l'argomento ma lo rimandiamo ad un articolo successivo.




                Windows e Java

                Python è nato originariamente in ambiente Unix, come supporto per un progetto in cui i linguaggi esistenti non erano adeguati, e si è diffuso quando l'autore (Guido Van Rossum) ha reso disponibile il linguaggio in sorgente su UseNet (le News di Internet). Però il Python non è legato ad Unix in maniera così forte come il Perl, e infatti il linguaggio si trova a suo agio senza scomporsi anche in altri ambienti. In particolare sono disponibili due interessanti implementazioni: il PythonWin per Windows e il JPython per Java. Il PythonWin è innanzitutto il porting del Python in ambiente Windows, corredato di una sorta di IDE e di librerie specifiche per Windows. Si può vedere in Figura 1 uno snapshot ottenuto con il PyhonWin che dimostra come esso consenta di accedere ad una buona parte della API di Win32. PythonWin ha numerose altre armi al suo arco, tra cui l'accesso all'OLE Scripting: di conseguenza si può usare Python per le ASP ma anche per scriptare Word o Excel.

                Figura 1
                Il Python può anche essere utilizzato per scriptare la Java Platform: esiste infatti una reimplementazione in Java, chiamata JPython. In questo contesto l'interprete Python tradizionale, che è scritto in C, viene chiamato CPython, e il JPython è la versione dell'interprete in Java. La cosa interessante è la compatibilità tra le versioni: infatti il JPython e il CPython usano le stesse librerie! Una cosa interessante è che il JPython consente di avere accesso con assoluta semplicità alle librerie Java e può essere quindi utilizzato per sperimentare interattivamente con Java. Per esempio ecco un listatino che crea una finesta con un bottone digitato direttamenete al prompt del JPython:




                >>> import java

                >>> from java import awt

                >>> f = awt.Frame("Demo")

                >>> b = awt.Button("Ok")

                >>> l = awt.Label("Hello")

                >>> f.add("Center", l)

                >>> f.add("South", b)

                >>> f.setSize(100,100)

                >>> f.setVisible(true)

                >>> f.setVisible(1)




                Conclusioni

                Non concluderò l'articolo dicendo che vale la pena di provarlo perchè arricchisce la vostra cultura. Io il Python lo uso, per progetti reali e in contesti commerciali. Mi limiterò a raccontare come ho cominciato ad usarlo. Devo dire che quando ho dato una buona occhiata al Python ero molto scettico ma anche abbastanza frustrato: avevo perso alcune ore per risolvere un baco in uno script Perl in teoria da cinque minuti, dovuto al fatto che non avevo afferrato bene un dettaglio sintattico. Più ci pensavo più mi sembrava assurdo che dopo quattro anni che lavoravo con il Perl, ancora non ne avevo digerito completamente la sintassi. Quella sintassi così stramba per me è un impiccio che costringe ad avere sempre il manuale sottomano (non mandatemi email dicendomi che non siete d'accordo, vi prego!). Perché nessuno aveva ancora inventato un linguaggio di scripting chiaro e pulito come Java?

                Mi serviva un linguaggio di scripting (Java non è un linguaggio di scripting) innanzitutto portabile tra Unix e NT, che avesse la stessa plasticità del Perl, con strutture dati primitive potenti come tabelle hash e liste. Il linguaggio che cercavo doveva gestire bene le stringhe, con espressioni regolari comprese nel linguaggio, e doveva essere interpretabile senza alcuna ricompilazione in modo da poter scrivere uno script ed eseguirlo anche con solo l'editor (o meglio ancora con il cat >file o il copy con: file). Come il Perl il linguaggio doveva essere poco tipizzato per non perdere tempo a fare dichiarazioni e progettazione per semplici script (per esempio in Java solo per impostare un pattern tipo *.txt o un event-handler occorre dichiarare una classe!). Questo fantomatico linguaggio doveva avere una sintassi più pulita e un orientatamento agli oggetti decisamente più netto e meno arzigogolato del Perl. E se fosse dotato anche di una shell con la quale interagire (mancanza del Perl - per farlo si deve lanciare il debugger!) non sarebbe stato male. Infine, possibilmente si doveva trattare di linguaggio che avesse qualche supporto, ovvero non il solito linguaggetto geniale tirato fuori da qualche ricercatore che non usa nessuno. Avevo sentito parlare del Python e del fatto che era abbastanza usato, ma mi ci volevano un paio di giorni per studiarlo. Quando finalmente ho trovato il tempo e ho avuto modo di approfondire meglio il linguaggio, ho capito di aver trovato quello che cercavo. E a giudicare dal supporto che circola su Internet, a quanto pare non sono il solo.




                Bibliografia

                [1] http://www.python.org - " Python Software Activity", il sito principale del Python dove si può trovare di tutto relativo al Python

                [2] Guido Van Rossum "Programming Python", O'Reilly 1997, il libro ufficiale sul Python scritto dall'autore del linguaggio.

                Uno sguardo al Python
                parte seconda

                di Michele Sciabarrà



                Se l'introduzione di Python della volta scorsa vi è parso interessante, questa seconda parte è una buona occasione per approfondirlo. Ovviamente non abbiamo alcuna pretesa di essere esaustivi, non potendo trattare un completo linguaggio di programmazione in 10 pagine, esempi compresi. Tuttavia questi due articoli dovrebbero essere sufficienti a muovere i primi passi e decidere se vale la pena continuare. Entriamo subito nel vivo esaminando le caratteristiche un po' più avanzate concernenti programmazione ad oggetti e la gestione degli errori. Vedremo infatti che Python pur nella sua grande semplicità è orientato ad oggetti in maniera così decisa che è stato proposto come linguaggio standard per lo scripting di oggetti distribuiti CORBA.




                Istanze

                Abbiamo visto i moduli, ovvero file che contengono definizioni di funzioni e altri comandi. Creando un nuovo file, chiamato per esempio modulo.py, contenente la definizione di funzione f(), è possibile importarlo con import modulo per poi chiamare la funzione f usando la sintassi modulo.f(). Per inciso, il file è importabile se la directory che lo contiene si trova nel PYTHONPATH. L'impostazione del PYTHONPATH varia da sistema a sistema, ma generalmente si tratta di impostare la variabile di ambiente PYTHONPATH. Notare che f in questo caso è una funzione, non un metodo o altro, anche se per accedervi occorre utilizzare il prefisso modulo. Un modulo è infatti un esempio di namespace; gli elementi in un namespace sono detti attributi. Per accedere ad un elemento di un namespace si utilizza la sintassi namespace.attributo. I builtin (per esempio dir) si trovano nel namespace __builtins__., e sono accedibili (come caso particolare) anche se non si specifica un prefisso. Un altro modo per evitare il prefisso è utilizzare from <namespace> import <attribute>, ma è meglio non abusare di questa facility per non avere problemi di collisioni di nomi.

                Le istanze delle classi sono anche essi dei namespace, anche se si comportano in maniera più sofisticata dei moduli. Si tratta in un certo senso della naturale evoluzione della programmazione modulare verso la programmazione ad oggetti. Nel resto dell'articolo si assumono basi di OOP: non spiegheremo che cosa è una classe, una istanza, un costruttore o una funzione virtuale, per cui se siete a digiuni di queste nozioni potreste incontrare qualche difficoltà nella lettura.

                Abbiamo visto che in Python ci sono svariati tipi di dato, come le sequenze, i dizionari, e i moduli. Adesso introdurremo un nuovo tipo di dato, ovvero la classe. Prima vediamo come si usano le classi esistenti, poi esamineremo come si definiscono nuove classi. Sfruttiamo l'aspetto interattivo del Python, che ci consente di imparare cose nuove sperimentando con l'interprete a riga di comando. Come esperimento per imparare l'uso di oggetti preleveremo ed esamineremo una pagina Web con una connessione http, usando la classe HTTP del modulo httplib:




                >>> import httplib

                >>> httplib.HTTP

                <class httplib.HTTP at 874be0>

                >>> h = httplib.HTTP("192.168.1.1")

                >>> h

                <httplib.HTTP instance at 875930>




                Innanzitutto notiamo che le classi, come le funzioni, sono contenute dentro moduli. In particolare la classe HTTP è contenuta nel modulo httplib, per cui occorre importare il modulo (altrimenti tale classe non è accessibile). Valutando httplib.HTTP osserviamo che si tratta di un oggetto di tipo classe, utilizzabile però in maniera analoga ad una funzione. Chiamando la classe, otteniamo un oggetto di tipo istanza della classe, come si vede nell'esempio. In pratica la classe è una funzione costruttore che produce istanze. L'oggetto istanza così costruito si comporta in maniera simile ad un modulo, ovvero come contenitore di funzioni che possono essere chiamate. In realtà un oggetto è qualcosa di più di un modulo, in quanto mantiene uno stato separato per ogni istanza. Quindi la classe è la naturale evoluzione del concetto di modulo: un oggetto è un namespace analogamente ad un modulo. La differenza principale è che si possono creare istanze diverse dello stesso modulo, ottenendo namespace separati con variabili indipendenti. Questo è il punto cruciale. I dati contenuti in una istanza di una classe vengono inizializzati chiamando una particolare funzione di inizializzazione: __init__. L'ultimo elemento importante che differenzia le classi dai moduli è il fatto che su di esse si può applicare l'ereditarietà, come vedremo più avanti. Riassumendo:



                • Namespace: spazio di nomi, contenente attribuiti; agli attributi di un namespace si accede con la sintassi namespace.attributo.
                • Modulo: namespace, che contiene funzioni e altri elementi, letto da un file.
                • Classe: una funzione in grado di generare istanze, ovvero un costruttore.
                • Istanza: namespace che contiene funzioni dette metodi; l'istanza differisce dal modulo per il fatto che viene creata dinamicamente (mentre i moduli sono definiti con dei file) e che gli attributi sono indipendenti per ogni istanza, anche se l'istanza viene creata dallo stesso costruttore.
                • Metodo:funzione appartenente ad una classe, che solitamente modifica le variabili dell'istanza a cui appartiene (in altre parole cambia lo stato dell'oggetto).

                Torniamo al nostro esempio, e utilizzando l'istanza di HTTP chiamandone i metodi:




                >>> h.putrequest('GET', '/')

                >>> h.endheaders()

                >>> h.getreply()

                (200, 'OK', <mimetools.Message instance at 876bc0>)

                >>> f = h.getfile()

                >>> lines = f.readlines()

                >>> lines[0]

                '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\012'




                Di ogni oggetto, per usarlo occorre conoscerne il funzionamento leggendone la documentazione. Nel caso che stiamo esaminando adesso, una istanza di HTTP invia delle richieste corrispondenti ai comandi HTTP. Questa classe in realtà non maschera molto il protocollo http, in quanto occorre conoscerlo almeno per sommi capi. In particolare, occorre sapere che la richiesta per prelevare una pagina web è GET, seguita dall'URL della pagina senza l'indirizzo dell'host. Dopo la richiesta, occorre anche aggiungere delle informazioni supplementari che vengono date al Web Server utilizzando degli header. Nel nostro caso non inviamo alcuna informazione supplementare, completando la richiesta con endheader(), e leggiamo la risposta del Web Server. Poiché è OK (codice 200, stringa di messaggio OK, altre informazioni nella istanza mimetools.Message) possiamo leggere la pagina web tramite un oggetto file per la lettura. Per semplicità, leggiamo le righe ponendole in una lista, e ne stampiamo solo la prima.




                Classi

                Impariamo adesso a creare nuove classi. Nel caso più semplice possiamo dichiarare una classe vuota:




                >>> class Void:

                ... pass

                ...

                >>> x = Void()

                >>> x

                <__main__.Void instance at 85ff80>

                >>> x.a

                Traceback (innermost last):

                File "<interactive input>", line 0, in ?

                AttributeError: a

                >>> x.a=1

                >>> y = Void()

                >>> y.a=2

                >>> print x.a,y.a

                1 2




                Utilizzando la keyword class abbiamo dichiarato una nuova classe, in questo chiamata Void. In una definizione di classe possono esserci comandi di qualsiasi genere, che vengono eseguiti durante la definizione della classe. I comandi per noi interessanti comunque sono quelli che dichiarano attributi, ovvero variabili e funzioni che diventano campi e metodi della classe. Gli altri comandi possono servire per esempio a definire dei metodi condizionalmente (per esempio in un modo sotto Windows e un altro sotto Unix) ma è meglio non abusare di queste possibilità.

                Ad una classe non vengono assegnati una volta e per tutte tutti i suoi attributi, ma possono essere aggiunti anche dopo che l'istanza è stata creata. Infatti in genere gli attributi vengono aggiunti in fase di inizializzazione. Come si vede nel'esempio, dopo aver dichiarato la classe, utilizziamo la funzione costruttore, avente lo stesso nome della classe, per creare nuove istanze. Nell'esempio utilizzando Void come funzione abbiamo creato l'istanza. Ogni instanza è un namespace separato che inizialmente non contiene alcun attributo. La natura dinamica del Python ci consente di aggiungere, "al volo", nuovi attribuiti, nell'esempio a. Che le istanze siano namespace separati e indipendenti si vede anche dal fatto che creando due istanze, possiamo assegnare ad ogni istanza un valore diverso per l'attribuito a. Otteniamo, come ci si aspetta, due a separati e indipendenti per ogni istanza.
                Last edited by Ribosio80; 29-03-2005, 02:12:18.

                Commenta

                • Ribosio80
                  Bodyweb Senior
                  • Oct 2003
                  • 8257
                  • 226
                  • 51
                  • dalle nubi
                  • Send PM

                  #9
                  Listato 1


                  class List:


                  def __init__(self, data, next=None):


                  self.data=data


                  self.next=next





                  def append(self, data):


                  curr = self


                  while not curr.next is None:


                  curr = curr.next


                  curr.next = List(data)


                  return self






                  def push(self, data):


                  return List(data,self)










                  def printall(self):


                  while not self is None:


                  print self.data


                  self=self.next


                  Le classi divengono interessanti quando contengono campi e metodi. Nel Listato 1 possiamo vedere la dichiarazione di una classe List, contenuta nel file list.py, che andiamo subito ad utilizzare:




                  >>> import list

                  >>> x = list.List(2)

                  >>> x.printall

                  <method List.printall of List instance at 8654a0>

                  >>> x.printall()

                  2

                  >>> x = x.push(1)

                  >>> x.printall()

                  1

                  2

                  >>> x=x.append(3)

                  >>> x.printall()

                  1

                  2

                  3




                  Come si vede, abbiamo definito una classe lista con tre metodi: append, push e printall. Esaminiamo ora in dettaglio il meccanismo della definizione della classe. Dichiarando una classe ci ritroviamo con una funzione costruttore che ha lo stesso nome della classe. In realtà questo costruttore crea soltanto l'oggetto istanza, ma non lo inizializza. Se occorre effettuare delle inizializzazioni supplementari (caso abbastanza frequente), si deve definire una funzione di inizializzazione che si deve chiamare __init__. L'uso dei doppi underscore all'inizio e alla fine è una convenzione Python usata ovunque sia necessario definire nomi che hanno un significato speciale, e non è limitata solo a questo caso. La __init__ viene chiamata automaticamente dopo che è stata creata l'istanza dell'oggetto.

                  Veniamo ora a quello che è un punto critico, ed è basilare per comprendere tutto il meccanismo della OOP in Python. Dovrebbe essere chiaro come funzionano in Python le funzioni (non c'è niente di speciale, a parte il fatto che sono solitamente contenute dentro dei moduli). Ora, nelle classi non ci sono funzioni ma metodi. In OOP, in generale i metodi sono funzioni speciali, in quanto conoscono l'oggetto a cui appartengono. In Java, C++ e altri linguaggi OOP l'accesso all'oggetto corrente è implicito e nascosto: il programmatore non se ne accorge. In Python invece l'oggetto corrente viene passato esplicitamente come primo parametro della chiamata del metodo. Confrontando l'ultimo esempio con il listato il meccanismo dovrebbe diventare abbastanza chiaro. Precisamente, scrivendo x = list.List(2) si costruisce un oggetto istanza, poi viene chiamato automaticamente __init__(self, data, next=None). Il primo parametro di __init__ è l'oggetto appena costruito, il secondo è il parametro fornito al costruttore (2). In questo esempio si utilizza anche la feature dei parametri di default: poiché non abbiamo specificato il terzo parametro questo assume il valore di default None. Il meccanismo è analogo quando invochiamo i metodi: chiamato x.printall() viene chiamata la funzione printall passando x come primo parametro. Per convenzione il primo parametro di un metodo viene chiamato self. Non c'è niente di speciale in questo nome ma non seguire questa convenzione può compromettere la leggibilità del vostro listato ad altri programmatori Python. Non ci sono modi per accedere direttamente ai campi di un oggetto: occorre usare sempre il prefisso self. Per quanto questa cosa possa apparire noiosa, in pratica questo migliora la leggibilità e evita ambiguità con le variabili locali.




                  Ereditarietà

                  L'ereditarietà è il meccanismo che consente di riutilizzare codice già esistente organizzato in classi: grazie ad essa possiamo creare nuove classi che estendono e modificano quelle esistenti. Esemplifichiamo il funzionamento, considerando una classe Punto2D, che estendiamo per ottenere un Punto3D:




                  import math

                  class Punto2D:

                  def __init__(self, x, y):

                  self.x = x

                  self.y = y

                  def dist(self):

                  return math.sqrt(self.x **2 + self.y **2)

                  class Punto3D(Punto2D):

                  def __init__(self, x, y, z):

                  Punto2D.__init__(self, x, y)

                  self.z = z

                  def dist(self):

                  return math.sqrt(Punto2D.dist(self)**2 + self.z**2)

                  Per ereditare da una classe si usa la sintassi class Derivata(Base1,Base2), dove Derivata è la classe che eredita dalle classi Base1 , Base2. Nell'esempio di sopra è mostrato un caso di ereditarietà singola ma Python supporta in generale l'ereditarietà multipla. La nuova classe eredita tutti i metodi delle classi base, il che significa che un metodo disponibile in una Base1 o Base2 è disponibile anche nella classe Derivata. Un metodo può trovarsi anche in più di una delle classi base: in tal caso viene usato il metodo trovato effettuando una ricerca deep-first nel grafo delle classi.

                  La cosa importante è che ereditando possiamo ridefinire i metodi della classe base, come si vede nell'esempio, dove il metodo dist di Punto3D ridefinisce il metodo dist di Punto2D. Per accedere ai metodi della classe base (operazione necessaria per sfruttare il codice preesistente) si deve far riferimento esplicitamente al metodo chiamandolo con il nome della classe e passando self come parametro. Nell'esempio si nota come vengano chiamati esplicitamente Punto2D.dist e Punto2D.__init__. Infine accenniamo al fatto che Python supporta anche l'operator overloading: è possibile per esempio ridefinire l'operatore + definendo il metodo __sum__, l'operatore * ridefinendo il metodo __mult__ e così via. Non trattiamo in dettaglio queste caratteristiche per ragioni di spazio.




                  Eccezioni

                  Durante l'esecuzione dei programmi possono insorgere degli errori. Linguaggi tradizionali come il C o il Pascal non prendono particolari provvedimenti per gestirli (è compito del programmatore "stare attento" e verificare bene i valori ritornati per riconoscere e gestire gli errori). In pratica però una condizione di errore è sempre qualcosa di particolare che altera il normale flusso del programma, e che tende a sfuggire all'attenzione del programmatore. Queste condizioni eccezionali, in pratica così eccezionali non sono, e devono essere in qualche modo gestite perché i programmi diventino robusti (ovvero non si piantano ogni 5 minuti). Non a caso i "disastri a catena" che avvengono nei programmi hanno origine in qualche errore non gestito che si propaga causando errori su errori fino alla terminazione del programma (nei casi fortunati) o il blocco del sistema (di solito). Per gestire le condizioni di errore è stato inventato, fin dai tempi antichi dell'informatica (vent'anni fa), il meccanismo delle eccezioni. Per molto tempo però la gestione delle eccezioni è rimasta confinata ai linguaggi assembler: da qualche anno è approdata anche ai linguaggi ad alto livello, come C++, Java e, appunto, Python.

                  Vediamo come funzionano le eccezioni considerando la gestione di un errore tanto semplice quanto (spesso) inaspettato: una divisione per zero:




                  >>> x = 0

                  >>>

                  >>> 1/x

                  Traceback (innermost last):

                  File "<interactive input>", line 0, in ?

                  ZeroDivisionError: integer division or modulo

                  >>> try:

                  ... y = 1/x

                  ... except ZeroDivisionError:

                  ... print "cannot divide!"

                  ...

                  cannot divide!

                  >>> ZeroDivisionError

                  <class exceptions.ZeroDivisionError at 7687e0>




                  In caso di eccezione, l'esecuzione si interrompe e causa la stampa di un messaggio di errore. Per essere esatti, durante l'esecuzione di un programma una eccezione causa il ritorno dalla funzione o metodo in cui ci si trova e la generazione di un eccezione nel punto in cui si ritorna. Questo meccanismo viene ripetuto, portando ad un ritorno forzato da tutte le chiamate correnti finché non si raggiunge il toplevel (che causa la terminazione con un messaggio errore), a meno che l'eccezione non venga in qualche modo catturata e gestita. In questo modo le condizioni di errore non sono ignorabili a meno che il programmatore non decida esplicitamente di ignorarle. Comunque in questo mod si tende a confinare gli errori in precisi sottosistemi che non causano la terminazione anomala del programma. Nell'esempio vediamo anche come funziona il meccanismo di gestione delle eccezioni: si sottopone a controllo il blocco che può causare l'eccezione tramite try. Le eccezioni possono essere provocate esplicitamente utilizzando raise. Se scatta una eccezione, questa viene confrontata con le possibili eccezioni che si vogliono gestire, usando la clausola except. Non ci deve essere necessariamente una sola clausola except ma anzi è utile che ce ne sia più d'una. Scatterà quella corrispondente al tipo di eccezione sollevato. Se nessuna va bene, l'eccezione si propaga come se non ci fosse stato alcun controllo. Questa procedura è anche il modo più corretto di gestirla: controllare gli errori che si prevedono e lasciar passare quelli inaspettati in modo che in fase di test e debug si possano rilevare le condizioni di errore non previste. Accenniamo infine al fatto che in Python la try può anche avere le clausole else e finally. La else viene eseguita se il codice sottoposto a try non causa eccezioni. La clausola finally invece viene eseguita in ogni caso, sia nel caso che il codice causi eccezioni, sia nel caso che tutti fili liscio. È anche possibile utilizzare classi definite dall'utente per organizzare gerarchicamente le eccezioni. Anche questo non lo trattiamo in dettaglio per motivi di spazio.




                  Esempio: Gestione Form

                  Concludiamo l'articolo con un esempio un po' più dettagliato e significativo: un piccolo programma che può essere usato per i vostri script Web di gestione form. Tengo a precisare che l'esempio qui pubblicato è stato scritto utilizzando Windows 98 con Personal Web Server. L'unico accorgimento per utilizzarlo in questo ambiente è quello di aggiungere al registro la key

                  "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\W3SVC\Parameters\Script Map\.py" con valore di tipo stringa "C:\Python\Python.exe %s", e di porre i vostri script in una directory web-shared con il permesso execute attivato. Lo script comunque ha girato senza problemi sotto Linux. In questo caso è stato usato il meccanismo del bang-path, ovvero inserire come prima riga del codice il riferimento all'interprete dello script con il prefisso #! Una schermata dello script è visibile in Figura 2, mentre lo script stesso è nel Listato 2.

                  Figura 2



                  Listato 2


                  #!/usr/bin/python







                  # Parameters


                  REREFER="http://192.168.1.4/python/form.py"







                  # imports


                  import cgi


                  import string







                  # Print the Form


                  def print_form(err, nome, cognome,
                  email):








                  print """


                  <head><title>Modulo
                  Richiesta di Informazioni</title></head>


                  <body>


                  <h1>Modulo Richiesta
                  Informazioni</h1>


                  Si prega di specificare i suoi
                  dati.<br>


                  Verrà rincontattato al più
                  presto.<hr>


                  """







                  if err:


                  print "<h2><b>Errore
                  nel modulo:</b> <tt>"+err+"</tt></h2>"







                  # output form with current fields


                  print """


                  <form action='%s'>


                  <table>


                  <tr><td>Nome:


                  <td><input type="text"
                  name="nome" size="20" value="%s"><br>


                  <tr><td>Cognome:


                  <td><input type="text"
                  name="cognome" size="20" value="%s"><br>


                  <tr><td>Email:<br>


                  <td><input type="text"
                  name="email" size="20" value="%s"><br>


                  <tr><td colspan=2
                  align=center><input type="submit" name="invia"
                  value="INVIA">


                  </table>


                  </form>


                  """ % (REREFER, nome,
                  cognome, email)







                  def form_check(form):







                  err = ""


                  nome = ""


                  cognome = ""


                  email = ""







                  if not form.has_key("nome"):


                  err = err + "<br>Specificare
                  il nome"


                  else:



                  nome = form["nome"].value


                  if not form.has_key("cognome"):


                  err = err + "<br>Specificare
                  il cognome"


                  else:



                  cognome = form["cognome"].value


                  if not form.has_key("email"):


                  err = err + "<br>Specificare
                  l'email"


                  else:



                  email = form["email"].value


                  if string.find(email, "@")
                  == -1:


                  err = err + "<br>Il
                  formato della email non e' corretto"





                  return (err, nome, cognome, email)












                  def send_mail(form):


                  email = """


                  Nome.....: %s


                  Cognome..: %s


                  Email....: %s


                  """ %
                  (form['nome'].value, form['cognome'].value, form['email'].value)


                  print """


                  <head><title>Modulo
                  Richiesta di Informazioni</title></head>


                  <body>


                  <h1>Conferma Richiesta</h1>


                  E' stata inviata la seguente richiesta
                  di informazioni:<hr>


                  <pre>%s</pre>


                  """ % (email)


                  # send mail here...







                  # Always


                  print "Content-type:
                  text/html\n\n<html>"







                  form = cgi.FieldStorage()


                  (err, nome,cognome,email) =
                  form_check(form)







                  if form.has_key("invia"):


                  if err:


                  print_form(err, nome, cognome, email)


                  else:


                  send_mail(form)


                  else:


                  # first run


                  print_form("",nome, cognome,
                  email)












                  print "<hr>La ringraziamo
                  per la preferenza accordataci.<br>Cordiali Saluti.</html>"


                  Spendiamo due parole sul funzionamento dello script anche perché il Python è posizionabile come una alternativa al Perl, e gli script CGI sono probabilmente il campo di applicazione più immediato del Python. Nel nostro script abbiamo utilizzato il modulo standard cgi per decifrare i parametri dello script. Come è noto il protocollo CGI invia i dati in un formato encrittato non particolarmente user-friendly. Chiamando form = cgi.FieldStorage viene costruito un oggetto contente i parametri passati allo script decifrati. A questo oggetto è possibile accedere come array associativo, estraendo i campi della form: form["nome"], eccetera. Attenzione che se si accede ad un campo non definito si ottiene una eccezione, per cui occorre verificare l'esistenza di una chiave usando form.has_key("nome"). Nello script abbiamo anche usato altre due feature del Python adatte alla generazione di pagine Web: il triple quote """ e l'operatore di I/O %. Per inserire in uno script Python stringhe di testo contenenti newline si deve usare come delimitatore tre virgolette. Un altro aspetto importante è che la print stampa una stringa, e le stringhe sono in Python immutabili. Per cui, anche se è possibile, fare "taglia e cuci" con le stringhe per comporre la pagina di output, è abbastanza inefficiente e scomodo. Per ovviare, esiste un meccanismo di output analogo alla printf del C, che illustriamo con un esempio:




                  >>> x = 1

                  >>> y = 'hello'

                  >>> z = 64

                  >>> print "x=%d y=%s z=%c" % (x,y,z)




                  La stringa che segue il print contiene delle specifiche di formato, composte dal % seguito da un carattere: d indica i numeri decimali, s le stringhe e c i caratteri. Le specifiche di formato vengono sostituite dai parametri che seguono l'operatore % dopo la stringa. Nell'esempio vediamo come il %d venga sostituito dal valore decimale di x, il %s dalla stringa y mentre il %c genera il carattere il cui codice ascii è contenuto nella variabile z (il codice ascii di '@' è appunto 64).




                  Conclusioni

                  Il Python sta crescendo molto ed occupa ormai un posto rispettabile nel mondo dei linguaggi di scripting, ormai quasi al pari del più noto Perl. In effetti, una chiara prova della diffusione del linguaggio è data da freshmeat.net, un sito che pubblica il nuovo freeware disponibile in rete: freshmeat riportava 10 nuovi package Perl recenti e ben 8 Python� Come dire, il linguaggio si avvicina in popolarità e diffusione al Perl e conquista ogni giorno nuovi cultori. Spero con questi articoli di aver contribuito alla sua diffusione, con lo scopo non di proporre un poco utile linguaggio per passare qualche momento di relax, ma uno ottimo strumento da utilizzare in pratica per risolvere ben precise categorie di problemi (nella fattispecie scripting Web, System Adminstration e supporto alla programmazione).

                  Commenta

                  • Ayurvedi77
                    Bodyweb Senior
                    • Apr 2002
                    • 1632
                    • 19
                    • 6
                    • Pisa
                    • Send PM

                    #10
                    Si ok ma magari posta i link invece del testo delle guide
                    ___________________


                    Codice:
                    apt-get remove brain
                    apt-get install windows-Vista
                    ___________________

                    Commenta

                    • zuperman
                      Zuper Hero
                      • May 2003
                      • 17204
                      • 364
                      • 274
                      • Burundi/usr/bin
                      • Send PM

                      #11
                      Propongo di modificare il titolo del post in "Delphi?? NO! Phyton. Istruzioni per l'uso"

                      Che ne dite? Modifico?
                      Allenamento e dieta fanno di te un atleta

                      Commenta

                      • Nesquik
                        Bodyweb Advanced
                        • Jan 2003
                        • 401
                        • 3
                        • 0
                        • /home/nesquik
                        • Send PM

                        #12
                        ecco, io mi sto studiacchiando il tcl da qualche tempo e ora mi fate venire le voglie per il python... ...stardi...
                        .
                        RFC Project aspetta il tuo contributo

                        Originariamente Scritto da JPP
                        io non sono umano, io sono l'ex Signore dei Bordelli e trascendo la materia fallace. In me alberga lo spirito di Lord Byron. Rassegnati, a me l'errore è negato

                        Commenta

                        • Ayurvedi77
                          Bodyweb Senior
                          • Apr 2002
                          • 1632
                          • 19
                          • 6
                          • Pisa
                          • Send PM

                          #13
                          Ragazzi la migliore guida al momento (perfetta per i neofiti della programmazione), è: "Pensare da informatico. Imparare con Python".
                          Siccome sono buono, bello e piacevolmente intrigante, eccovi il PDF

                          C'è anche questo, decisamente più breve...
                          ___________________


                          Codice:
                          apt-get remove brain
                          apt-get install windows-Vista
                          ___________________

                          Commenta

                          • Ribosio80
                            Bodyweb Senior
                            • Oct 2003
                            • 8257
                            • 226
                            • 51
                            • dalle nubi
                            • Send PM

                            #14
                            il link sopra se lo clicchi ci sono tutti e 2.....


                            ps si fanno ottime cosucce

                            Commenta

                            • Ayurvedi77
                              Bodyweb Senior
                              • Apr 2002
                              • 1632
                              • 19
                              • 6
                              • Pisa
                              • Send PM

                              #15
                              Tutorial PyGTK (inglese):


                              Un discreto IDE:
                              Eric3

                              Un'altro:
                              SPE - Stani's Python Editor

                              Un'altro ancora:
                              Boa-Constructor
                              ___________________


                              Codice:
                              apt-get remove brain
                              apt-get install windows-Vista
                              ___________________

                              Commenta

                              Working...
                              X