Python_ Introduzione Al Linguaggio - Parte II - Mimante

17
24/2/2015 Python: introduzione al linguaggio Parte II mimante.net http://www.mimante.net/doc/py/obj.html 1/17 home page doc obj Avviso! Questo articolo è basato su una versione obsoleta di python; può ancora essere utile come tutorial basilare, ma non copre le molte features introdotte nel corso degli ultimi anni. A volte ritornano A parte citare film horror, in questa seconda parte (che originalmente segue la prima , nella quale abbiamo introdotto questo interessante linguaggio interpretato) vedremo come poterlo utilizzare seguendo i paradigmi della programmazione ad oggetti. La cosa. Anzi, le cose Gli oggetti nei linguaggi di programmazione sono né più né meno che astrazioni degli oggetti del mondo reale. Nel caso abbiate difficoltà a concepire oggetti fisici, vi consiglio un corso intensivo di immersione nella realtà e tempo una dozzina d'anni dovreste essere in grado di proseguire la lettura di questo articolo. Esattamente come gli oggetti fisici (avete presente la caffettiera che vi rifornisce del carburante fondamentale ad ogni programmatore?) anche quelli che andremo a creare programmando avranno caratteristiche (come potrebbero essere il colore, la marca, il materiale, le dimensioni, etc.) e saranno in grado di compiere azioni (aprirsi, ricevere acqua, chiudersi, scaldare l'acqua, esplodere...) A grande richiesta direi si possa passare alla presentazione di un piccolo esempio, rimandando ai commenti del codice l'ingrato mestiere di spiegare i dettagli implementativi della programmazione ad oggetti e della sintassi del python. Miva! Lanciami i componenti! Quello che segue è un modulo che ci sarà utile come base su cui creare altre applicazioni; per il semplice motivo che più avanti lo utilizzeremo con questo nome, siete pregati di far conto che il file in cui è salvato si chiami cibolib.py. Prima che mi copriate di insulti: sono perfettamente conscio che come esempio non è un granché, ma non è facile farsi venire idee originali per un esempio di programmazione ad oggetti che debba occupare poche linee di codice; inoltre lo stile di programmazione è volutamente essenziale e non ho certo puntato a creare una applicazione solida o ben progettata: semplicemente ho cercato di inserirvi elementi che ritenevo interessanti da mostrare, lasciando alla buona volontà del lettore il compito di approfondire gli argomenti secondo le sue necessità; discorso analogo andrebbe fatto circa la terminologia usata, che in alcuni punti si discosta da quella formale nel tentativo di aggiungere chiarezza all'esposizione. Anche alcuni sottili dettagli vengono ignorati, omessi o semplificati: questo vuole essere un articolo introduttivo e non certo un'analisi approfondita del linguaggio. """Definisce le classi necessarie ad un pranzo sano, completo e nutriente. Ecco lo schema di derivazione delle classi: Cibo |

description

Python_ Introduzione Al Linguaggio - Parte II - Mimante

Transcript of Python_ Introduzione Al Linguaggio - Parte II - Mimante

Page 1: Python_ Introduzione Al Linguaggio - Parte II - Mimante

24/2/2015 Python: introduzione al linguaggio ­ Parte II ­ mimante.net

http://www.mimante.net/doc/py/obj.html 1/17

home page doc obj

Avviso!Questo articolo è basato su una versione obsoleta di python; può ancora essere utile come tutorialbasilare, ma non copre le molte features introdotte nel corso degli ultimi anni.

A volte ritornano

A parte citare film horror, in questa seconda parte (che originalmente segue la prima, nella qualeabbiamo introdotto questo interessante linguaggio interpretato) vedremo come poterlo utilizzareseguendo i paradigmi della programmazione ad oggetti.

La cosa. Anzi, le cose

Gli oggetti nei linguaggi di programmazione sono né più né meno che astrazioni degli oggetti delmondo reale. Nel caso abbiate difficoltà a concepire oggetti fisici, vi consiglio un corso intensivo diimmersione nella realtà e tempo una dozzina d'anni dovreste essere in grado di proseguire la lettura diquesto articolo. Esattamente come gli oggetti fisici (avete presente la caffettiera che vi rifornisce delcarburante fondamentale ad ogni programmatore?) anche quelli che andremo a creare programmandoavranno caratteristiche (come potrebbero essere il colore, la marca, il materiale, le dimensioni, etc.) esaranno in grado di compiere azioni (aprirsi, ricevere acqua, chiudersi, scaldare l'acqua, esplodere...)

A grande richiesta direi si possa passare alla presentazione di un piccolo esempio, rimandando aicommenti del codice l'ingrato mestiere di spiegare i dettagli implementativi della programmazione adoggetti e della sintassi del python.

Miva! Lanciami i componenti!

Quello che segue è un modulo che ci sarà utile come base su cui creare altre applicazioni; per ilsemplice motivo che più avanti lo utilizzeremo con questo nome, siete pregati di far conto che il filein cui è salvato si chiami cibolib.py.Prima che mi copriate di insulti: sono perfettamente conscio che come esempio non è un granché, manon è facile farsi venire idee originali per un esempio di programmazione ad oggetti che debbaoccupare poche linee di codice; inoltre lo stile di programmazione è volutamente essenziale e non hocerto puntato a creare una applicazione solida o ben progettata: semplicemente ho cercato di inserirvielementi che ritenevo interessanti da mostrare, lasciando alla buona volontà del lettore il compito diapprofondire gli argomenti secondo le sue necessità; discorso analogo andrebbe fatto circa laterminologia usata, che in alcuni punti si discosta da quella formale nel tentativo di aggiungerechiarezza all'esposizione. Anche alcuni sottili dettagli vengono ignorati, omessi o semplificati: questovuole essere un articolo introduttivo e non certo un'analisi approfondita del linguaggio.

"""Definisce le classi necessarie ad un pranzo sano, completo e nutriente.

Ecco lo schema di derivazione delle classi:

Cibo|

Page 2: Python_ Introduzione Al Linguaggio - Parte II - Mimante

24/2/2015 Python: introduzione al linguaggio ­ Parte II ­ mimante.net

http://www.mimante.net/doc/py/obj.html 2/17

+‐‐ Primo+‐‐ Secondo+‐‐ Dolce

Author: Davide Alberani <[email protected]>Updated: 32 febbraio dell'anno prossimo."""

from types import *import sys

# scala di qualitàqual = ['ripugnante', 'fetente', 'media', 'buona', 'ottima']

class Cibo: """Classe generica; meglio non istanziarne oggetti.

Definisce i seguenti metodi: get_nome() restituisce il nome del piatto. set_nome(string) setta il nome del piatto. get_calorie() riporta il numero di calorie per unità di quantità. set_calorie(int) indovinate. get_calorie_totali() restituisce le calorie totali. get_quanto() restituisce la quantità. set_quanto(int) setta la quantità. get_come() ci dice la bontà del piatto. set_come(int) fa qualcosa di impensabile. """

def __init__(self): self.nome = '' self.calorie_per_unita = 0 self.quantita = 0 self.qualita = qual.index('buona') def get_nome(self): return self.nome def set_nome(self, n): if type(n) is not StringType: print '"' + n + '" non è un nome valido' sys.exit(1) self.nome = n def get_calorie(self): return self.calorie_per_unita def set_calorie(self, c): if type(c) is not IntType or c < 0: print '"' + c + '" non è un valore valido per le calorie' sys.exit(1) self.calorie_per_unita = c def get_calorie_totali(self): return self.calorie_per_unita * self.quantita def get_quanto(self): return self.quantita def set_quanto(self, x): if type(x) is not IntType or x < 0: print 'Posso dubitare del fatto che "' + x + \ '" sia una quantità valida?' sys.exit(1) self.quantita = x def get_come(self): return self.qualita def set_come(self, q): if type(q) is not IntType: print 'Errore nella definizione della qualità' sys.exit(1) if q >= len(qual) or q < 0:

Page 3: Python_ Introduzione Al Linguaggio - Parte II - Mimante

24/2/2015 Python: introduzione al linguaggio ­ Parte II ­ mimante.net

http://www.mimante.net/doc/py/obj.html 3/17

print 'Valore di qualità fuori dal range' sys.exit(1) self.qualita = q

class Primo(Cibo): """Per creare un oggetto primo piatto.""" # qualche caratteristica specifica. brodo = 0 formaggio = 0

class Secondo(Cibo): """Particolarità dei secondi piatti.""" pesce = 0 def e_un_pesce(self): return self.pesce def set_pesce(self, v): if type(v) is not IntType: print 'Non sei né carne né pesce...' sys.exit(2) if v != 0 and v != 1: print 'Valore fuori range' sys.exit(2) self.pesce = v

class Dolce(Cibo): """Classe derivata per i dolci (slurp).""" porzioni = 0 def __init__(self, n, p): """Inizializzazione.""" if type(p) is not IntType or p < 0: print '"' + p + '" non è un numero valido' sys.exit(3) self.set_nome(n) self.set_quanto(50 * p) self.set_come(4) self.set_calorie(4) self.porzioni = p def get_calorie_totali(self): """Ridefinisce questa funzione.""" return self.calorie_per_unita * self.quantita * self.porzioni

Niente panico

C'è un bel po' di carne al fuoco; vediamo di fare ordine con calma e metodo.L'inizio del file non dovrebbe spaventare: una semplice docstring su più linee che descrive leprincipali caratteristiche di questo modulo, ovvero le classi, le funzioni e le costanti che definisce piùqualche informazione sull'autore e sul file stesso.

Modulo aereo!

Di cosa sono e a cosa servono i moduli abbiamo già discusso, e come si vede crearne uno èestremamente semplice: basta scrivere il codice che ci interessa in un file la cui estensione sia .py, perpoi inserirlo in una delle directory in cui l'interprete python lo cercherà.Una cosa nuova che noterete dopo aver testato l'intero piccolo progetto che vi sto presentando comeesempio è che per motivi di prestazione i moduli, se possibile, vengono pseudocompilatidall'interprete python la prima volta che sono richiesti, lasciando nella medesima directory un file conlo stesso nome del modulo ma con estensione .pyc; in questo modo la successiva volta che uno scriptpython includerà il dato modulo questo non dovrà essere nuovamente letto e compilato, ma si userà

Page 4: Python_ Introduzione Al Linguaggio - Parte II - Mimante

24/2/2015 Python: introduzione al linguaggio ­ Parte II ­ mimante.net

http://www.mimante.net/doc/py/obj.html 4/17

direttamente il .pyc.Ovviamente vengono fatti i dovuti controlli sulle date dei file in modo da assicurarsi che il filesorgente non sia stato nel frattempo modificato (nel qual caso ovviamente si procederà a nuovaricompilazione).

Proseguiamo con l'analisi del sorgente: le righe import dovrebbero esservi chiare; come sempre invitoa riferirsi alla documentazione dei vari moduli per approfondirne l'uso.Vediamo ora qualcosa di cui non avevamo ancora parlato:

linea 14 | qual = ['ripugnante', 'fetente', 'media', 'buona', 'ottima']

Uno strano tipo

Python include una serie di tipi di dati predefiniti molto utili. Quella che abbiamo appena definito èuna lista di nome qual i cui elementi sono le stringhe racchiuse tra le parentesi quadre separati davirgole.Prima di addentrarci nella programmazione ad oggetti, vediamo quali sono questi tipi e come possonotornarci utili.

Sequenza di autodistruzione attivata...

Esistono tre tipi diversi di sequenze: le stringhe, le liste e le tuples (un termine italiano che vi siavvicini come significato potrebbe essere ennuple, ma preferisco attenermi alla denominazioneoriginale).Le stringhe e le tuples sono tipi di dati immutabili (ovvero non è possibile modificare direttamente iloro elementi, anche se esistono vari "trucchi" per ottenere risultati analoghi) mentre le liste sono untipo di dato mutabile.

StringheNon guardatevi le scarpe: le stringhe non sono altro che una serie di caratteri alfanumerici uno diseguito all'altro. Come già visto le stringhe in python vengono create semplicemente includendo icaratteri tra coppie di 'apici singoli', "doppi apici" o """tripli apici""" per testi su più righe.Le stringhe possono essere concatenate tra loro con l'operatore + (ad esempio 'Ciao ' + 'mondo' saràequivalente a 'Ciao mondo'; in realtà se i due elementi adiacenti sono stringhe il + può essere omesso,ma il programma non ne guadagna in leggibilità) e ripetute con * ('Ciao' * 3 risulterà uguale a'CiaoCiaoCiao'). È possibile accedere alla stringa tramite degli indici (racchiusi tra parentesi quadre,che oltre a semplici numeri di indice possono contenere anche degli intervalli, separati da due punti);qualche esempio dovrebbe chiarire tutti i casi tipici:

stringa = 'Ciao mondo!'

# solo il primo carattereprint stringa[0]

==> C

# il secondo carattereprint stringa[1]

==> i

Page 5: Python_ Introduzione Al Linguaggio - Parte II - Mimante

24/2/2015 Python: introduzione al linguaggio ­ Parte II ­ mimante.net

http://www.mimante.net/doc/py/obj.html 5/17

# l'ultimo carattereprint stringa[‐1]

==> !

# il penultimo carattereprint stringa[‐2]

==> o

# dal sesto al settimo carattere (estremi inclusi)print stringa[5:7]

==> mo

# i primi quattro caratteriprint stringa[:4]

==> Ciao

# tutta la stringa tranne i primi tre caratteriprint stringa[3:]

==> o mondo!

# gli ultimi due caratteriprint stringa[‐2:]

==> o!

# tutta la stringa tranne gli ultimi tre caratteriprint stringa[:‐3]

==> Ciao mon

Riferirsi al solito tutorial per i casi particolari e la gestione di eventuali errori.

Liste

Le liste sono elenchi di dati, anche di tipo diverso, ed è possibile modificare i singoli elementi di unalista e anche variarne il numero. Anche qui possiamo accedere agli elementi tramite indici e intervalli,sempre ricordandosi che il primo elemento è il numero zero. Qualche esempio:

lista = ['fagioli', 5, 2, 'gatti']

print lista[0]

==> fagioli

# "tagliando" una lista si ottiene una nuova listaprint lista[1:]

==> [5, 2, 'gatti']

# modificare un elementolista[1] = 'peperoni'print lista

==> ['fagioli', 'peperoni', 2, 'gatti']

# altre operazioni sulle liste

Page 6: Python_ Introduzione Al Linguaggio - Parte II - Mimante

24/2/2015 Python: introduzione al linguaggio ­ Parte II ­ mimante.net

http://www.mimante.net/doc/py/obj.html 6/17

# elimina un elementodel lista[2]print lista

==> ['fagioli', 'peperoni', 'gatti']

# aggiunge un elementolista.append('cani')print lista

==> ['fagioli', 'peperoni', 'gatti', 'cani']

Come c'era da aspettarsi anche per le liste funzionano gli operatori +, * e alcuni altri metodi specifici:count(obj) restituisce il numero di campi della lista che hanno valore obj, index(obj) restituisce ilprimo indice in cui viene trovato l'oggetto obj, remove(obj) rimuove il primo oggetto obj dalla lista,reverse() e sort() che rispettivamente rovesciano e ordinano la lista. È inoltre possibile effettuaresostituzioni e modifiche ai vari elementi di una lista utilizzando degli intervalli come riferimento.

Tuples

Sono elenchi simili alle liste, ma sono immutabili; i vari elementi sono racchiusi tra parentesi tonde eseparati da virgole, anche se nelle dichiarazioni le parentesi possono essere omesse. Come al solitoqualche esempio:

t1 = 'abc', 3, 56, 'ciao't2 = (2, 4, 5, 'gatto')

print t1

==> ('abc', 3, 56, 'ciao')

print t2==> (2, 4, 5, 'gatto')

# tuple di un solo elemento (singoletto, singleton in originale)t3 = ('solo',)

# tuple vuotat4 = ()

È interessante vedere come gli elementi di una tuple possano essere "spacchettati" (in originale "tupleunpacking", in contrapposizione al processo di creazione di una tuple, detto "tuple packing") in modomolto semplice assegnando i vari elementi a variabili separate:

t = 'primo', 'secondo, 'terzo'

# NB: il numero di variabili a sinistra deve corrispondere# con il numero di elementi della tuplee1, e2, e3 = t

print e1

==> primo

Qualcosa di analogo può essere fatto anche sugli elementi di una lista, con la sintassi:

Page 7: Python_ Introduzione Al Linguaggio - Parte II - Mimante

24/2/2015 Python: introduzione al linguaggio ­ Parte II ­ mimante.net

http://www.mimante.net/doc/py/obj.html 7/17

lista = ['primo', 2, 3][var1, var2, var3] = lista

print var1

==> primo

Da ricordare infine che su tutti i tipi di dati visti finora sono validi alcuni operatori e metodi standardcome obj in seq (la sua negazione è not in) che restituisce vero se l'oggetto obj è contenuto nellasequenza di dati seq; len(seq) che ne restituisce il numero di elementi; min(seq) e max(seq) cherestituiscono rispettivamente il valore minore e maggiore tra quelli contenuti nella sequenza.

Dizionari

Un diverso tipo di dato sono i dizionari, composti da coppie di keyword: valore, dove keyword deveessere unica all'interno del vocabolario.Un piccolo esempio, per presentarne le peculiarità:

# definiamo un dizionario che ad ogni soggetto associa la sua etàanni = 'Maria': 30, 'Giovanna': 18, 'Lucia': 21, 'Sandra': 24

# legge un valoreanni['Maria']

==> 30

# cambia un valoreanni[Giovanna] = 19

# cancella una vocedel anni['Lucia']

# verifica se una chiave è contenutavero_o_falso = anni.has_key('Margarita Cansino')

# crea una lista contenente solo le keywordslista_nomi = anni.keys()

# lista con solo i valorilista_valori = anni.values()

# restituisce una lista di tuples di due elementi (chiave, valore)lista_coppie = anni.items()

Diamo i numeri

Un tipo di dati che abbiamo ampiamente utilizzato ma su cui non ci siamo soffermati, in fondo perchédi solito li si considera scontati, sono i numeri. Python definisce gli interi, i long, i float e i complessi.Gli interi sono implementati internamente come i long in C: tutti i numeri che non ricadano nelle altrecategorie vengono di default considerati interi. I long vengono specificati aggiungendo al numero ilsuffisso l o L (è consigliata la seconda forma, per non rischiare di confondere la elle minuscola con lacifra uno) e non hanno limiti di dimensioni. I float sono tutti i numeri che abbiano una parte decimale.I complessi sono sempre considerati come dei double in C; la parte immaginaria è indicata dal suffissoj o J, i numeri che hanno sia parte reale che immaginaria possono essere creati con la funzionecomplex(re, im) o più semplicemente sommando un intero o float ad una parte immaginaria; sarà poi

Page 8: Python_ Introduzione Al Linguaggio - Parte II - Mimante

24/2/2015 Python: introduzione al linguaggio ­ Parte II ­ mimante.net

http://www.mimante.net/doc/py/obj.html 8/17

possibile accedere alle due parti tramite le notazioni numero.real e numero.imag.Python si occupa in maniera trasparente all'utente di effettuare le opportune conversioni di tipoquando necessarie; in ogni caso sono disponibili alcune funzioni built­in per forzarle, come adesempio int(n), long(n), float(n).

linea 15 | class Cibo:

Che classe!

Veniamo finalmente alla descrizione di cosa sono e come si costruiscono le classi e gli oggetti da essederivate. Un oggetto classe definisce un tipo generico di oggetti; la sintassi è molto simile alledichiarazioni di funzioni, dove al posto dell'istruzione def si utilizza class. Le classi possono essereconcepite come "idee" o descrizioni generiche di oggetti; da queste verranno poi istanziati gli oggettiveri e propri. Al loro interno le classi possono contenere dichiarazioni di variabili e di funzioni,secondo necessità. Per amor di formalità va ricordato che in python le funzioni appartenenti ad unaclasse vengono chiamate metodi quando vengono richiamate tramite un oggetto istanziato (comeabbiamo già visto) e l'insieme di funzioni e variabili è detto attributi.

linea 28 | nome = ''linea 29 | calorie_per_unita = 0linea 30 | quantita = 0linea 31 | qualita = qual.index('buona')

Qui vengono dichiarate alcune variabili utili a descrivere le caratteristiche dell'oggetto Cibo, come sivede si può far riferimento senza problemi a variabili esterne precedentemente definite.

linea 32 | def get_nome(self):linea 33 | return self.nomelinea 34 | def set_nome(self, n):linea 35 | if type(n) is not StringType:linea 36 | print '"' + n + '" non è un nome valido'linea 37 | sys.exit(1)linea 38 | self.nome = n

Queste sono le dichiarazioni di un paio di funzioni: la prima restituisce il contenuto della variabilenome mentre la seconda la modifica dopo aver fatto i controlli del caso sul tipo passato comeparametro.

Usare le classi e derivarne oggetti

La classe in sé è un oggetto: è possibile accedere alle sue variabili e utilizzarne le funzioni; adesempio possiamo riferirci alla variabile Cibo.nome e leggerla e modificarla a nostro piacimento.Molto più interessante e pratico è invece istanziare oggetti partendo da una classe; la sintassi che sisegue è analoga a quella usata per le normali funzioni. Esempio chiarificatore:

# creiamo l'oggetto antipasto, istanza della classe Cibo.# NB: le parentesi sono MOLTO importanti, se omesse si# creerà solamente un altro riferimento all'oggetto classe Cibo.antipasto = Cibo()

# chiamiamo il metodo set_nome() proprio dell'oggetto antipastoantipasto.set_nome('nuvole di drago')

Page 9: Python_ Introduzione Al Linguaggio - Parte II - Mimante

24/2/2015 Python: introduzione al linguaggio ­ Parte II ­ mimante.net

http://www.mimante.net/doc/py/obj.html 9/17

# leggiamo il valore precedentemente registratonome1 = antipasto.get_nome()print nome1

==> nuvole di drago

Come si vede, nel codice che la definisce la funzione accetta un parametro (self), mentrenell'invocazione questo non viene specificato: molto semplicemente quando viene invocato un metododi un oggetto istanziato, viene nella pratica chiamata la funzione propria della classe con l'oggettostesso come primo argomento (e tutti gli argomenti passati dall'utente a seguire). Infatti le sintassi:

# sintassi 1 (viene invocato il metodo dell'oggetto)antipasto1.set_nome('aria fritta')

# sintassi 2 (viene usata la funzione definita nella classe)Cibo.set_nome(antipasto2, 'aria molto fritta')

# sintassi 1nome1 = antipasto1.get_nome()

# sintassi 2nome2 = Cibo.get_nome(antipasto2)

sono del tutto equivalenti; entrambe le metodologie di lavoro con gli oggetti sono perfettamente lecite.Nell'esempio il primo parametro nelle definizioni di funzione viene sempre denominato self e vieneusato nel corpo delle funzioni per riferirsi ad altri attributi dell'oggetto stesso; il nome è del tuttoarbitrario, anche se per coerenza e leggibilità sarebbe opportuno seguire questa convenzione.

Il resto del codice della classe Cibo non dovrebbe presentare difficoltà anche per i meno esperti; unicanota da sottolineare sulla sintassi è l'istruzione:

linea 52 | print 'Posso dubitare del fatto che "' + x + \linea 53 | '" sia una quantità valida?'

Che come si vede è divisa su più righe per migliorare la leggibilità del codice: la barra rovesciataindica all'interprete che l'istruzione prosegue alla riga seguente; può essere omessa quando ciò che siva a spezzare è contenuto in parentesi di vario genere (liste, tuples, dizionari, parametri di funzioni,etc.)

linea 66 | class Primo(Cibo):linea 67 | """Per creare un oggetto primo piatto."""linea 68 | # qualche caratteristica specifica.linea 69 | brodo = 0linea 70 | formaggio = 0

Ciiiro! Figlio mioooo!

Le classi servirebbero a ben poco se non fosse possibile crearne di nuove senza dover riscriverel'intero codice, ma solo modificando una classe generica aggiungendovi solo le peculiarità richiestedal nuovo tipo di oggetto generando così una gerarchia ramificata di classi.In questo esempio definiamo la classe Primo come derivata dalla classe Cibo da cui eredita (questomeccanismo si chiama infatti ereditarietà) tutti gli attributi; in più vi aggiunge le proprie variabili e le

Page 10: Python_ Introduzione Al Linguaggio - Parte II - Mimante

24/2/2015 Python: introduzione al linguaggio ­ Parte II ­ mimante.net

http://www.mimante.net/doc/py/obj.html 10/17

proprie funzioni (vedere anche la classe derivata Secondo). La classe da cui se ne deriva un'altra(Cibo, in questo caso) è detta classe base.Ovviamente ogni oggetto di queste classi derivate potrà indistintamente accedere a variabili e funzionidefinite tanto nella classe da cui ha ereditato (come ad esempio il metodo set_nome()) quanto a quelledefinite nel proprio corpo (come la variabile formaggio).Altra funzionalità molto utile è la possibilità di sovrascrivere un metodo definito nella classe "madre"in modo da modificarne il comportamento; un esempio in merito lo potete vedere analizzando lafunzione get_calorie_totali() della classe Dolce alla riga 97.

Ereditarietà multipla

È anche possibile che una nuova classe debba ereditare da più classi base; la sintassi del python anchein questo caso è molto semplice: è sufficiente indicare tra parentesi il nome di tutte le classi da cui sieredita separate da virgole. Ad esempio:

class Coltellino_Svizzero(Coltello, Accetta, Motosega, Cavatappi): . . .

Da notare che questa tecnica, seppure potente, può portare a conflitti tra variabili e metodi definiti inpiù classi che creerebbero errori difficilmente identificabili; è quindi bene usarla con cautela e solodopo aver attentamente progettato sulla carta lo schema di derivazione. Per gli scopi di questo articolobasti ricordare che quando si cercherà di accedere ad un attributo di un oggetto appartenente ad unaclasse derivata da più classi, questo viene cercato, se non definito dalla classe a cui ci si riferisce, nelleclassi da cui questa deriva in ordine da sinistra a destra rispetto a come specificate tra le parentesidella dichiarazione. Ad esempio invocando il metodo sradica() di un oggetto Coltellino_Svizzeroquesto viene cercato, se non definito nella classe Coltellino_Svizzero stessa, prima nella classeColtello, poi in Accetta e così via.

linea 87 | def __init__(self, n, p):linea 88 | """Inizializzazione."""linea 89 | if type(p) is not IntType or p < 0:linea 90 | print '"' + p + '" non è un numero valido'linea 91 | sys.exit(3)linea 92 | self.set_nome(n)linea 93 | self.set_quanto(50 * p)linea 94 | self.set_come(4)linea 95 | self.set_calorie(4)linea 96 | self.porzioni = p

Spesso è utile, istanziando un oggetto da una classe, eseguire alcune funzioni di default, inizializzaredelle variabili e così via; questo può essere fatto tramite il metodo __init__(), che viene eseguitoquando un oggetto viene istanziato. In questo esempio quando andremo ad istanziare un oggettoDolce dovremo passare due parametri, rispettivamente una stringa che ne rappresenti il nome e ilnumero di porzioni. Può essere una buona idea utilizzare nella dichiarazione dei valori di default per ivari parametri. Per chiarire, potremmo cambiare il codice in questo modo:

def __init__(self, n='Torta della nonna', p=1): . . .

Page 11: Python_ Introduzione Al Linguaggio - Parte II - Mimante

24/2/2015 Python: introduzione al linguaggio ­ Parte II ­ mimante.net

http://www.mimante.net/doc/py/obj.html 11/17

A questo punto sarebbero ugualmente accettabili le invocazioni:

a = Dolce()b = Dolce('Tiramisù')c = Dolce('Torta di mele', 2)

Variabili private

Chi ha già esperienza di programmazione orientata agli oggetti con altri linguaggi come C o Java avrànotato che la sintassi e l'implementazione di questi concetti in python è molto meno complessa estringente: gran parte del lavoro necessario ad un corretto uso degli oggetti è lasciato all'utente stesso,che è libero di comportarsi come meglio crede. Una caratteristica che subito salta agli occhi è lapossibilità di accedere sempre e comunque a tutti gli attributi di un oggetto, senza limitazioni diaccesso e senza possibilità di nascondere i dati all'interno delle classi stesse. Questo non è del tuttovero: anche in python è possibile utilizzare quelle che in C vengono chiamate variabili (e funzioni)private; qualsiasi attributo il cui nome cominci con due underscore e termini con al più un underscoreviene considerato privato, e quindi non accessibile direttamente dall'esterno. Un esempio:

class Gino: # variabile privata __pippo = 4 # metodo per accedere in lettura alla variabile __pippo dall'esterno def get_pippo(self): return self.__pippo

x = Gino()

# leggiamo il valore di __pippo tramite la funzione prepostaprint x.get_pippo()

==> 4

# un accesso diretto porterà ad un erroreprint x.__pippo

==>Traceback (innermost last): File "./prova", line 13, in ? print x.__pippoAttributeError: __pippo

è bene tenere a mente che, per come questa funzionalità è implementata in python, con estremasemplicità è comunque possibile un accesso diretto ai dati, quindi non si può fare affidamento sullaloro intoccabilità che è ancora una volta lasciata alla buona volontà del programmatore.

Usi avanzati degli oggetti

Come in molti altri linguaggi anche in python è possibile ottenere comportamenti piuttosto complessiper quanto riguarda gli oggetti; ad esempio si può, sovrascrivendo opportuni metodi, gestire le regoleche sovraintendono al confronto tra due oggetti distinti, consentire un accesso ai dati di un oggettotramite notazioni ad indice simili a quelle delle sequenze viste sopra, sovrascrivere gli operatorimatematici in modo da garantire un comportamento coerente con le caratteristiche degli oggetti stessie molto altro ancora; tutto questo va ben oltre gli scopi introduttivi di questo articolo e rimando quindigli interessati al Python Reference Manual, in particolare alla sezione 3.3 Special method names.

Page 12: Python_ Introduzione Al Linguaggio - Parte II - Mimante

24/2/2015 Python: introduzione al linguaggio ­ Parte II ­ mimante.net

http://www.mimante.net/doc/py/obj.html 12/17

Usiamo il nostro modulo

#!/usr/bin/python

# importiamo il nostro modulofrom cibolib import *import sys, string, pickle

# lista di un menulista_piatti = []

def domande_standard(oggetto): """Domande da porre sia per i primi che per i secondi piatti""" try: nome = raw_input('Nome: ') oggetto.set_nome(nome) cal = raw_input('Calorie per unità di peso: ') oggetto.set_calorie(int(cal)) quant = raw_input('Quantità: ') oggetto.set_quanto(int(quant)) for i in range(len(qual)): print '\t' + `i` + '‐ ' + `qual[i]` q = raw_input('Qualità: ') oggetto.set_come(int(q)) except ValueError: print 'Uno dei valori immessi non è un numero' sys.exit(3)

primo = Primo()print '\nDefinisci un primo:\n'# pone le domande standarddomande_standard(primo)# pone le domande specifiche per i primi piattibrodo = raw_input('è in brodo? [s/n] ')if brodo[0] == 's': primo.brodo = 1form = raw_input('Una spolveratina di formaggio? [s/n] ')if form[0] == 's': primo.formaggio = 1# aggiunge questo oggetto alla lista dei primi piattilista_piatti.append(primo)

secondo = Secondo()print '\nDefinisci un secondo:\n'domande_standard(secondo)pesce = raw_input('È un pesce? [s/n] ')if pesce[0] == 's': secondo.set_pesce(1)else: secondo.set_pesce(0)lista_piatti.append(secondo)

# i dolcinome_dolce = raw_input('\nNome del dolce: ')porzioni = raw_input('Numero di porzioni del dolce: ')try: dolce = Dolce(nome_dolce, int(porzioni))except ValueError: print 'Numero di porzioni errato' sys.exit(4)lista_piatti.append(dolce)

# stampa le calorie delle singole portate e il totale

Page 13: Python_ Introduzione Al Linguaggio - Parte II - Mimante

24/2/2015 Python: introduzione al linguaggio ­ Parte II ­ mimante.net

http://www.mimante.net/doc/py/obj.html 13/17

print '\n\tMENU DEL GIORNO\n\t‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐\n'

# calorie totalical_tot = 0

for i in lista_piatti: cal = i.get_calorie_totali() print string.rjust(`i.get_quanto()` + 'grammi di ' + i.get_nome() + '| ', 40) + `cal` + 'calorie' cal_tot = cal_tot + cal

print string.rjust('‐‐‐|‐', 40) + '‐‐'

print string.rjust('Calorie totali: | ', 40) + `cal_tot`

if primo.brodo: print 'Il primo è in brodo.'if primo.formaggio: print 'Sul primo c\'è del formaggio.'if secondo.e_un_pesce(): print 'Il secondo è un pesce.'

salva = raw_input('\nSalvo cotanta squisitezza? ')if salva[0] == 's': try: f = open('ultimo_menu', 'w') except IOError, errore: print 'Errore nell\'aprire il file di log', errore sys.exit(5) pickle.dump(lista_piatti, f) f.close()

What's goin on in the kitchen?

Ok, citeremo anche rapper, e allora?Una tipica sessione di uso del programma, apparirà simile a questa (in grassetto le parti digitatedall'utente):

$ ./cibo.py

Definisci un primo:

Nome: Spaghetti al ragùCalorie per unità di peso: 2Quantità: 150 0 ‐ 'ripugnante' 1 ‐ 'fetente' 2 ‐ 'media' 3 ‐ 'buona' 4 ‐ 'ottima'Qualità: 3È in brodo? [s/n] nUna spolveratina di formaggio? [s/n] s

Definisci un secondo:

Nome: Pollo arrostoCalorie per unità di peso: 3Quantità: 200 0 ‐ 'ripugnante'

Page 14: Python_ Introduzione Al Linguaggio - Parte II - Mimante

24/2/2015 Python: introduzione al linguaggio ­ Parte II ­ mimante.net

http://www.mimante.net/doc/py/obj.html 14/17

1 ‐ 'fetente' 2 ‐ 'media' 3 ‐ 'buona' 4 ‐ 'ottima'Qualità: 2È un pesce? [s/n] n

Nome del dolce: ProfiteroleNumero di porzioni del dolce: 2

MENU DEL GIORNO ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐

150 grammi di Spaghetti al ragù | 300 calorie 200 grammi di Pollo arrosto | 600 calorie 100 grammi di Profiterole | 400 calorie ‐‐‐|‐‐‐ Calorie totali: | 1300

Sul primo c'è del formaggio.

Salvo cotanta squisitezza? n

Il codice in sé dovrebbe essere immediatamente comprensibile; ci soffermeremo ora solo su alcunerighe che introducono novità o che hanno bisogno di qualche spiegazione in più.

linea 10 | nome = raw_input('Nome: ')

raw_input() è una funzione built­in che consente di catturare input da tastiera dopo aver presentatol'eventuale prompt specificato come argomento; per maggiori informazioni su questa e altre funzioniriferirsi alla documentazione delle librerie standard, sezione "Built­in Functions".

linea 16 | for i in range(len(qual)):

Anche la funzione range() è built­in nell'interprete python: serve a creare al volo una lista numerica dazero fino al valore specificato come argomento meno uno; può anche venir indicato un numero dipartenza ed un eventuale passo per gli incrementi.

linea 23 | primo = Primo()

Viene istanziato un oggetto della classe Primo.

linea 35 | lista_piatti.append(primo)

Aggiunge un oggetto alla lista creata in precedenza.

linea 60 | print string.rjust(`i.get_quanto()` + 'grammi di ' + i.get_nome() +linea 61 | '| ', 40) + `cal` + 'calorie'

Il modulo string contiene numerose funzioni per manipolare stringhe; in questo caso usiamo lafunzione rjust per giustificare a destra il testo creando una tabella più facilmente leggibile; come sivede i parametri richiesti sono semplicemente la stringa stessa e il numero di caratteri che formano ilcampo in cui giustificare il testo.

Page 15: Python_ Introduzione Al Linguaggio - Parte II - Mimante

24/2/2015 Python: introduzione al linguaggio ­ Parte II ­ mimante.net

http://www.mimante.net/doc/py/obj.html 15/17

linea 65 | if primo.brodo:linea 66 | print 'Il primo è in brodo.'linea 67 | if primo.formaggio:linea 68 | print 'Sul primo c\'è del formaggio.'linea 69 | if secondo.e_un_pesce():linea 70 | print 'Il secondo è un pesce.'

Due modi di accedere ai dati di un oggetto: le prime due istruzioni if accedono direttamente allevariabili, mentre l'ultima invoca un metodo.

linea 74 | f = open('ultimo_menu', 'w')

File

I file sono un altro tipo di oggetti predefinito in python; sono creati tramite l'istruzione built­in open()che richiede due argomenti entrambi stringhe: il primo sarà il nome del file, il secondo il tipo diaccesso che si desidera ('r' indica lettura, 'w' scrittura, 'r+' lettura e scrittura; nei sistemi Microsoft eMacintosh si può aggiungere alla stringa il suffisso b che sta ad indicare un accesso di tipo binario, adesempio 'r+b' apre un file in modalità binaria per lettura e scrittura); se il secondo argomento vieneomesso, l'accesso in sola lettura viene scelto come default.In caso di errori viene sollevata l'eccezione IOError.Una volta aperto il file, possiamo usare alcune funzioni per accedere al suo contenuto:

# apriamo il filef = open('MoanaStory.txt', 'r+')

# leggiamo tutto il suo contenutotutto = f.read()

# leggiamo la prima riga del file.# successive chiamate a questa funzione leggeranno# le righe seguenti.riga = f.readline()

# scritturaf.write('Tanto tempo fa, in una galassia molto, molto lontana...')

# chiudiamo il filef.close()

È possibile "spostarsi" all'interno del file indicando il byte su cui ci si vuole posizionare per poiiniziare la lettura o scrittura:

# si posiziona all'inizio del filef.seek(0)

# si posiziona al centesimo bytef.seek(100)

# si posiziona quattro byte dopo l'attuale posizionef.seek(4, 1)

# si posiziona a cinque byte dalla fine del filef.seek(5, 2)

Page 16: Python_ Introduzione Al Linguaggio - Parte II - Mimante

24/2/2015 Python: introduzione al linguaggio ­ Parte II ­ mimante.net

http://www.mimante.net/doc/py/obj.html 16/17

Come si vede il secondo argomento specifica come vada considerato il primo: se è 0 o omesso si usala posizione dall'inizio del file, se 1 si considera rispetto alla posizione attuale, se 2 si calcola rispettoalla fine del file. Se si desidera conosce la posizione corrente si deve ricorrere alla funzione tell().Tutte le funzioni che leggono dati da file (come read() e readline()) accettano un parametro opzionaleintero, che sta ad indicare il numero massimo di byte da leggere.

linea 78 | pickle.dump(lista_piatti, f)

Il modulo pickle torna utile in tutte quelle occasioni in cui si vogliano salvare dei dati per unsuccessivo riutilizzo. Quella che qui andiamo ad utilizzare è una funzione (il modulo mette adisposizione anche oggetti per ottenere risultati simili) che salva su un file precedentemente aperto inscrittura un qualsiasi oggetto. In seguito sarà possibile accedere ai dati salvati in maniera moltosemplice. Ad esempio:

#!/usr/bin/python

import pickle

f = open('ultimo_menu', 'r')

# carica l'oggetto salvatolista = pickle.load(f)

f.close()

# a questo punto potremo utilizzare lista# come siamo abituati a fare.

Il modulo pickle si presta ad usi molto più avanzati che potrete approfondire grazie alla LibraryReferences, dove c'è documentazione anche per moduli che implementano funzioni più o menoanaloghe come cPickle, shelve e marshal.

Conclusioni

Sperando di aver chiarito più dubbi di quanti non ne abbia creato, vi lascio sperimentare python dasoli e vi ricordo di tenere a portata di mano la vostra fida documentazione: python offre ancoramoltissime cose da scoprire come ad esempio moduli per le regular expression, per pressoché tutti iservizi di rete, compressione, numeri random e inoltre debugger, profiler, possibilità di integrazionecon Tk per creare interfacce grafiche, di integrazione col C e molto altro. Di alcune di queste cose(forse ;­) potrei parlare in futuri articoli.Come sempre invito a scrivermi senza ritegno a <[email protected]> per dubbi, domande esuggerimenti. Se riuscite a farle arrivare fresche anche le torte al cioccolato sono molto apprezzate. ;­)

Grande concorso: chi indovinerà tutte le citazioni cinematografiche/culturali presenti in questo testo avrà l'onore divenire pubblicamente deriso nel prossimo articolo! O forse no.

Link

Vaults of Parnassus : Python Resources: una marea di risorse per i programmatori.Cameron Laird's personal notes on Python: programmazione (in larga parte per la rete).Python Journal: aperiodico sul nostro linguaggio.

Page 17: Python_ Introduzione Al Linguaggio - Parte II - Mimante

24/2/2015 Python: introduzione al linguaggio ­ Parte II ­ mimante.net

http://www.mimante.net/doc/py/obj.html 17/17

Links2go: link su python.JPython: porting di python in java.Python things: librerie.Starship Python: librerie e manuali.Pythonware: compagnia che lavora molto con python.Python Special Interest Groups: progetti mantenuti dalla PSA.PyJava: Java Embedded in Python.Scripting Java with Python.IDLE: un IDE scritto in python.

[me | home | top | mimas]