




















Studia grazie alle numerose risorse presenti su Docsity
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Prepara i tuoi esami
Studia grazie alle numerose risorse presenti su Docsity
Prepara i tuoi esami con i documenti condivisi da studenti come te su Docsity
Trova i documenti specifici per gli esami della tua università
Preparati con lezioni e prove svolte basate sui programmi universitari!
Rispondi a reali domande d’esame e scopri la tua preparazione
Riassumi i tuoi documenti, fagli domande, convertili in quiz e mappe concettuali
Studia con prove svolte, tesine e consigli utili
Togliti ogni dubbio leggendo le risposte alle domande fatte da altri studenti come te
Esplora i documenti più scaricati per gli argomenti di studio più popolari
Ottieni i punti per scaricare
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Una panoramica introduttiva alla programmazione con python, concentrandosi su concetti fondamentali come i cicli, le funzioni e le liste. L'utilizzo dei cicli for, le diverse tipologie di parametri nelle funzioni, le operazioni sulle liste e la gestione delle matrici tramite liste di liste. Inoltre, vengono presentati esempi pratici per comprendere meglio l'applicazione di questi concetti.
Tipologia: Dispense
1 / 28
Questa pagina non è visibile nell’anteprima
Non perderti parti importanti!





















PROGRAMMAZIONE IN PYTHON – problem solving 19.09. Il primo ad essersi occupato di PROBLEM SOLVING è il matematico ungherese George Polya il quale era abituato a dimostrare teoremi e scrivere libri su quelle dimostrazioni. Il libro “How to solve it” è il primo libro che si è occupato del problem solving ed è proprio di Polya. Il ciclo del problem solving si compone di quattro passaggi:
La PROGRAMMAZIONE STRUTTURATA è rappresentata da blocchi di codice organizzati in maniera sistematica ed è formata da sole tre tipologie:
rappresenta la potenza (se scrivo 2**3 il risultato è 8). Tutti i calcoli di Python hanno come unico limite quello
Oltre ai dati numerici ci sono altre tipologie di dati. Per i VALORI BOOLEANI c’è il tipo bool che può assumere soltanto due valori: True o False (con l’iniziale maiuscola). A True è associato il numero 1 e a False
di verità:
vedere l’appartenenza di un elemento e len per valutare quanti elementi sono presenti nella lista. Ci sono due funzioni fondamentali in Python che permettono di chiedere e mostrare dei valori all’utente. La prima è la funzione INPUT che prende una riga di testo inserita dall’utente in una variabile, consente all’utente di immettere dati in tastiera, dati che poi verranno utilizzati dal programma. Quando si inserisce la funzione input essa blocca il programma finchè non è l’utente a scrivere qualcosa (ovviamente una stringa) e poi a premere invio. Se si desidera immettere valori numerici o di altri tipi, è possibile convertire la stringa restituita da input usando funzioni come int o float. La funzione PRINT serve per mostrare l’output all’utente, scrive una serie di valori su una riga inserendo lo spazio tra i parametri, i valori. ESEMPIO: si chieda all’utente come si chiama e quanti anni ha. PROGRAMMAZIONE IN PYTHON – moduli di Python (g2d) Il modulo permette anche di fare dei DISEGNI sullo schermo che non è altro che una griglia di pixel che possono essere colorati. Per capire a quale pixel fare riferimento si può usare una coppia di coordinate ma, a differenza del piano cartesiano ordinario, l’origine degli assi è in alto a sinistra quindi le x crescono verso destra ma le y crescono verso il basso ed inoltre gli indici di riga e colonna partono da 0 (se le colonne o le righe sono 50 vuol dire che l’ultima colonna o riga è la 49 perché è conteggiata anche la prima che è la zero). Per colorare un punto bisogna specificare il punto secondo il modello dei colori: i tre colori primari sono rosso, verde e blu e dalla combinazione di questi si ottengono quelli secondari (rosso + verde dà il giallo, rosso + blu dà il magenta, blu + verde dà il ciano, rosso + verde + blu dà il bianco). I colori hanno un range che va da 0 a
- Posizione: le coordinate di un punto di scrivono (x, y) - Dimensione: la dimensione di un oggetto è (larghezza, altezza) - Colore: per specificare il colore di un determinato oggetto si crea una tupla di tre valori Per quanto riguarda i colori la tupla è tripla ed è così formata: (rosso, verde, blu). Alcuni esempi standard: - (255, 0, 0) → colore rosso - (0, 255, 0) → colore verde - (0, 0, 255) → colore blu - (255, 255, 0) → colore giallo - (255, 0, 255) → colore magenta - (0, 255, 255) → colore ciano - Combinando poi i diversi colori se ne possono ottenere tanti altri. Prima di scrivere qualsiasi cosa bisogna importare g2d dunque la prima linea deve riportare la dicitura “import g2d”. successivamente bisogna inserire le dimensioni dello schermo sul quale si vuole ottenere qualcosa quindi inserire “g2d.init_canvas((larghezza, altezza))”. Pr i colori si digita “g2d.set_color((red, gree, blu))” con le varie componenti di colore. Poi è possibile disegnare e scrivere: - g2d.draw_rect((punto di inizio), (misura))
ESEMPIO: l’obiettivo è quello di disegnare una sequenza di n quadrati dove L è il lato del canvas noto mentre l è il lato dei quadrati noto. La posizione del primo quadrato è 0 (in alto a sinistra) e quella dell’ultimo quadrato è L – l. Come prima cosa si deve chiedere all’utente in numero n di quadrati da generare. Questi quadrati, a prescindere da quanti siano, devono occupare la diagonale e il loro colore deve essere sui toni del rosso partendo dal nero (saturo) fino al rosso acceso (255). In questo caso è utile il ciclo for per la sua linearità. Note la posizione del primo e dell’ultimo quadrato, gli altri vengono messi in una posizione intermedia che dipende dai passi del ciclo infatti è possibile calcolare pos_m = (pos_lst – post_fst)/max(n-1,1): l’ultimo quadrato meno il primo diviso quanti quadrati sono, il denominatore è scritto così per evitare una divisione per zero se n fosse uguale a 1. Poi si costruisce il ciclo for variabile rispetto al numero dei triangoli come in esempio. Lo stesso ragionamento fatto per la posizione lo si fa anche per il colore rosso: red_fst, red_lst = 0, 255. L’uso più comune del ciclo for utilizzato in questo modo è per gestire matrici oppure elementi grafici dove i passaggi sono ripetitivi. ESEMPIO: si vuole mostrare una griglia di rows x cols (righe per colonne) di rettangoli dove orizzontalmente il colore blu cresce da 0 a 255 e verticalmente il colore verde cresce da 0 a 255. In questo caso si devono creare due cicli annidati di valori lineari rispetto a x e y. Dopo aver definito la misura del canvas, dei rettangoli e la gradazione del colori si crea un primo ciclo for al quale si aggiunge un secondo ciclo for che chiede di disegnare i rettangoli con colori che si mischiano. PROGRAMMAZIONE IN PYTHON – cicli con sentinella Il valore SENTINELLA (o flag) è uno o più valori di controllo che identificano un caso eccezionale, è un indicatore che fa capire quando bisogna smettere di fare una determinata cosa oppure quando modificare qualcosa nel ciclo while. La sentinella è il valore scelto tendenzialmente quando si devono acquisire dei valori input in un ciclo. Il valore sentinella deve essere diverso dai dati e scelto in modo appropriato. ESEMPIO: il valore sentinella è - 1. Inizialmente si chiede all’utente un numero, se questo è diverso da - 1 allora lo si “stampa” elevato alla terza e si chiede nuovamente all’utente un numero. Questo ciclo può continuare ininterrottamente finchè non è immesso quel valore e quindi il ciclo finisce. Il codice input è presente due volte nel: prima di cominciare il ciclo e durante il ciclo dopo aver elaborato il valore corrente. Il ciclo for e il ciclo while sono due strutture intercambiabili ma, in determinati contesti, è preferibile usarne uno piuttosto dell’altro per una questione di leggibilità e codifica: il ciclo for viene usato quando si conosce il punto di inizio e di fine del ciclo, quando si deve “ciclare” su una stringa con dimensioni finita e quando si ha a che fare con range, tuple, liste; il ciclo while si usa quando non si conoscono i dati di inizio e fine del ciclo e quando c’è un input continuo dove non si sa quante volte si deve ripetere il ciclo oppure quando ci possono essere delle condizioni che implicano l’interruzione del ciclo. ESEMPIO: l’obiettivo è calcolare il massimo tra una sequenza di valori. Si assume come valore iniziale meno infinito quindi questo valore va importato dalla libreria math. Poi si costruisce un ciclo for dove se il valore è più grande di meno infinito allora quello prende il valore più grande e viene stampato.
22.10. PROGRAMMAZIONE IN PYTHON – le funzioni Una FUNZIONE è un operatore che viene applicato a degli operandi per ottenere un certo risultato. L’utilità delle funzioni è quella di rendere l’organizzazione di un programma più modulare cercando di astrarre il problema per trovare delle soluzioni il più generali possibili. La funzione deve essere definita ed implementata: bisogna definire il nome, gli operandi su cui operare e il risultato da restituire. Dopo aver creato la funzione bisogna poi utilizzarla. La sintassi di una funzione in Python è data da: def nome della funzione (inventata, per convenzione non deve iniziare con la lettera maiuscola) e tra parentesi tonde gli operandi su cui la funzione opererà, tutto questo è seguito dai due punti e a capo, dopo il tab, ci sono le istruzioni relative alla funzione. Dopo le istruzioni, a capo, c’è return per terminare l’esecuzione e restituire il risultato. Scrivere soltanto def permette di definire la funzione ma non di eseguirlo, bisogna quindi chiamarla. La funzione, quando viene eseguita crea nuovi spazi di nomi e i parametri e le variabili hanno ambito locale e non sono visibili nel resto del programma: la funzione randint restituisce un numero tra un minimo ed un massimo inseriti senza fare sapere o vedere quali variabili ausiliarie vengono create per la sua riuscita. È importate ricordarsi di assegnare il risultato di una funzione ad una variabile. Nelle funzioni ci sono due tipologie di parametri:
le definizioni delle funzioni della libreria g2d (quando g2d non era nella stessa cartella di Python infatti il programma dava errore). Se viene creata una funzione in un file e salvo il file con il nome mymath.py, è possibile poi aprire un nuovo file, scrivere import mymath e richiamare la funzione definita al suo interno. La sintassi è nome del modulo.nome della funzione: g2d.set_color, g2d.main_loop, mymath.hypotenuse. Il file g2d quando viene importato prevede che tutto ciò che è scritto al suo interno venga copiato, incollato ed eseguito. Siccome un file .py può essere sia una libreria sia un programma, per evitare comportamenti anomali Python prevede l’istruzione if _ _ name_ _ == “_ _ main_ _” che è una clausola di controllo che permette al codice di capire se è eseguito come modulo oppure come script: se c’è questo comando vuol dire che il modulo viene importato senza eseguire il main, altrimenti si esegue tutto il codice. Quando si scrive il programma in Python, l’interprete analizza il file per trovare eventuali errori ma gli unici che può trovare sono quelli strettamente di sintassi ma non è in grado di stabilire a priori se una funzione darà un errore o un risultato sbagliato. Siccome non esiste un modo per sapere a priori se ci sarà l’errore e siccome non si vuole che il programma si interrompa, può essere fatta una gestione degli errori manuale tramite l’istruzione raise : se si verifica una condizione sbagliata, invece che lasciare all’interprete di trovare il problema bloccando l’esecuzione, si gestisce l’errore manualmente stampando il messaggio di errore. Il vincolo dell’istruzione di errore raise è che l’utente che scrive il programma deve sapere quando si potrà verificare l’errore. Nel caso dell’esempio: poiché un triangolo è tale se un lato è minore della somma degli altri due, se si verifica questa condizione allora viene restituito il perimetro altrimenti viene mostrato il messaggio di errore. Le funzioni possono prendere in ingresso qualunque tipo di dato, qualunque numero e la stessa cosa vale per i valori di ritorno: possono essere uno, più di uno separati da virgole oppure tuple. Una funzione può anche presentare più istruzioni di return, non è però una buona prassi. L’utilità delle funzioni è quella di rendere tutto più modulare ma un suo limite è quella di fornire limitata astrazione, incapsulare un comportamento. È importante mettere in chiaro i parametri e i dati che servono: quando si scrive una funzione, quest’ultima vede i dati che sono riportati al suo esterno e li può modificare con le variabili globali ma questo può portare a delle complicazioni. ESEMPIO: si vuole definire una funzione per rimbalzi ovvero, quando la pallina animata tocca il bordo del canvas, rimbalza cambiando direzione. Dopo aver importato g2d e aver definito una serie di variabili, si definisce la funzione move_ball che permette di muovere la pallina all’interno del canvas: se la x non è compresa nel range dato allora cambia direzione e lo stesso vale per la y, ciò che viene restituito è una tupla di 4 valori. Si definisce poi la funzione tick che non prende in ingresso nessun valore ma che al suo interno prevede di avere delle variabili globali. Come ultimo step viene definita la funzione main che prevede di disegnare il canvas, e il main_loop(tick), chiamando main() la pallina rimbalza quando tocca i lati del canvas. La funzione deve essere sempre definita nel modo più lineare possibile facendo in modo che non siano presenti istruzioni che possano determinare comportamenti imprevedibili quando vengono eseguiti. Ci sono però due casi in cui questo può accadere:
valori diversi. Quando sono presenti più funzioni una dentro l’altra, quella che viene eseguita per prima è quella più interna esattamente come nelle espressioni matematiche. Gli effetti collaterali però possono trasformarsi in problemi non restituendo il valore corretto della funzione. 29.10. Esistono anche delle FUNZIONI TRIGONOMERICHE. Un punto può essere definito da coordinate polari o da coordinate cartesiane: le coordinate polari sono definite come la lunghezza del segmento e di un angolo rispetto al riferimento mentre le coordinate cartesiane sono le coordinate x e y nel piano. Per fare la conversione tra queste due tipologie si usa il seno e il coseno dell’angolo compreso tra un asse di riferimento. Da polari a cartesiane si usa il seguente sistema: {
e da cartesiane a polari: {
Questo concetto può essere sfruttato sul canvas per tracciare segmenti in forme complesse oppure per definire il movimento di un oggetto. ESEMPIO: l’obiettivo è tracciare una serie di segmenti che hanno in comune l’origine e che differiscono tra loro di un certo angolo. Dopo aver importato la libreria grafica g2d e i moduli che servono dalla libreria math viene definita una funzione che prende in ingresso tre valori interi: il punto di partenza, il punto di arrivo e la lunghezza della linea. Nella definizione della funzione è anche presente un ciclo for che permette di disegnare una linea per ognuno degli angoli digitati: in questo caso disegnerà 4 raggi dove il primo sarà orizzontale (angolo 0°), il secondo di 15°, il terzo di 30° e il quarto di 45°. Le ultime istruzioni date permettono di definire le dimensioni del canvas e disegnare i raggi. La funzione definita è generale ma risponde ad un problema specifico. L’obiettivo delle funzioni sarebbe quello di essere il più generali possibili quindi si vorrebbe che questa funzione funzionasse anche nel caso di coordinate polari e non sono nel caso di coordinate cartesiane. Tramite il simbolo = avviene l’assegnazione di un nome di una variabile ad un valore. Tramite questo operatore si possono anche definire nuove tipologie di dato che sono combinazioni dei tipi di dato base. Point e Polar sono due nuovi punti costituiti entrambi da una tupla formata da due float. Definire queste due tipologie di dato permette una maggiore leggibilità ed una maggior possibilità di generalizzare: nel caso di Point i due float rappresentano le coordinate cartesiane x e y, nel caso di Polar i due float rappresentano il raggio e l’angolo delle coordinate polari. ESEMPIO: l’obiettivo è scrivere la funzione precedente utilizzando altri moduli che generalizzino ulteriormente la funzione: vengono convertite le coordinate da polari a cartesiane e viene calcolata la posizione del finale dato il punto di partenza, la lunghezza e l’angolo. La prima funzione che viene definita restituisce le coordinate cartesiane partendo da quelle polari e le restituisce sotto forma di Point ovvero una tupla di due float. La funzione move_arount prende in ingresso il punto di inizio (dato di tipo Point), la lunghezza e l’angolo (dati di tipo float) e restituisce un punto ovvero il punto di partenza sull’asse x più il suo spostamento sull’asse x e il punto di partenza sull’asse y più il suo spostamento sull’asse y. Volendo definire draw_rays (la funzione dell’esempio precedente) tramite move_around si deve chiamare questa funzione dando in ingresso le coordinate iniziali sotto forma di tupla, il raggio e l’angolo (gli angoli sono quelli citati nel ciclo for) e ciò che viene disegnato è una linea. In definitiva si ottengono una serie di raggi con vertice in comune e ampiezza che varia a seconda degli angoli inseriti. L’ultima istruzione è la definizione della funzione main che prevede di disegnare il canvas, i raggi e il main_loop.
ESEMPIO: prendendo in considerazione l’esempio precedente delle palline che rimbalzano, l’obiettivo è quello di eliminare le variabili globali e avere meno dati in ingresso e in uscita. Dopo aver importato la libreria grafica g2d (unica cosa uguale) viene definita la classe Ball secondo la sua sintassi corretta. Il primo metodo della classe è il metodo di inizializzazione dove come parametri prende self (ordinario) e x0, y0. Self, in questo caso, si riferisce alla pallina. Per ogni pallina è bene definire la posizione iniziale, finale e la velocità sugli assi x,y (esattamente le variabili dell’esempio precedente). Poiché non avrebbe senso che tutte le palline partissero dallo stesso punto, le posizioni non sono fisse e quindi occorre definire i parametri x0 e y0 che vengono poi riportati anche nella parentesi della definizione. In questo caso si è deciso che le velocità sono invece le medesime per tutte le palline quindi, durante la definizione dei campi si associa direttamente un numero e non un parametro (se si fossero scelte velocità diverse per le palline allora bisognava creare altri parametri e aggiungerli alla parentesi). Dopo aver definito questa classe è possibile definire b1 e b2 che sono le palline (potrebbero essere n, un numero a piacere) con una nuova sintassi: b1 = Ball(n,n) dove Ball è il nome della classe e i valori sono x0 e y0 ovvero i parametri che sono stati aggiunti da me, se non avessi aggiunto parametri dopo il self allora le parentesi sarebbero rimaste vuote. Viene definita un’ulteriore funzione all’interno della classe Ball che deve permettere il movimento delle palline. Inizialmente c’erano una serie di if: uno per le x della pallina 1, uno per le x della pallina 2, uno per le y della pallina 1 e uno per le y della pallina 2. Nel nuovo codice definisco la funzione move che prende in ingresso il parametro self (obbligatorio) e deve restituire una tupla di quattro valori. I cicli if si riducono a due perché non c’è più la distinzione tra prima e seconda pallina, il ciclo serve per le x e poi per le y di tutte le palline che verranno secondariamente generate. Tutte le diciture x del primo codice vengono sostituite da self._x e lo stesso vale anche per y, dx e dy. Dopo aver definito i due cicli if che permettono i rimbalzi (quando la pallina tocca i bordi del canvas cambia direzione), devo aggiungere l’indicazione che le componenti x e y si devono aggiornare. Per poter fare questa cosa nel codice precedente avevo necessità di utilizzare le variabili globali, ora non più. Si può quindi poi definire b1.move e b2.move che permetteranno il movimento della pallina, all’interno delle parentesi non viene espresso nessun parametro perché, nella definizione di move all’interno della classe, l’unico parametro utilizzato è self. Viene infine definito il metodo pos all’interno della classe Ball, metodo che prende in ingresso solo il parametro self e restituisce una tupla di due valori int ovvero la posizione della pallina. Questo metodo deve produrre un risultato quindi necessità del return. Non è possibile scrivere soltanto b1.pos() ma a questo valore deve essere assegnata una variabile che permette poi di utilizzare il risultato. La variabile può essere chiamata pt1 (come in questo caso) e corrisponde ad una tupla oppure si può spacchettare la variabile nei due valori della tupla. La funzione tick è molto più chiara e leggibile perché i valori rimangono incapsulati all’interno della classe. Nella funzione tick viene pulito il canvas, definita la posizione delle palline e, tramite questa posizione, disegnate le stesse. Infine, si fanno muovere le palline come riportato dal metodo move. Le ultime due istruzioni sono tipiche di g2d e permettono di inizializzare il canvas con le sue dimensioni e il main_loop che prende in ingresso la funzione tick. Inizialmente il programma era dotato di una serie di variabili globali che, con la programmazione per oggetti, non servono più. Il codice risulta quindi più pulito e leggibile, non ci sono tanti dati in giro da gestire.
Il parametro SELF che viene inserito come primo parametro in ogni metodo è un valore che viene assegnato automaticamente da Python, self è anche l’oggetto su cui si va a fare una determinata operazione. Il sistema si crea un oggetto in memoria per la classe che è stata definita e crea anche una raccolta generica di informazioni sull’oggetto. Quando si scrive un programma, si scrive il metodo init ma non viene chiamato, è Python a fare questa cosa. Quindi:
dall’icona del fantasma invisibile. Dopo aver definito i metodi della classe si può passare a scrivere il programma: la funzione tick cancella in canvas e per ogni elemento in ghosts disegna un fantasma nella posizione, con la visibilità e con la grandezza definita dai metodi e poi il fantasma viene fatto muovere. Il ciclo for significa che, per ogni elemento della lista ghosts, si fanno determinate azioni e la lista ghost è definita all’interno della funzione main. La lista creata è vuota e poi, tramite un ciclo ripetuto 5 volte, si aggiungono alla lista tramite la funzione .append() i fantasmi creati dalla classe Ghost. Nella funzione main g2d e la lista ghosts vengono definiti come funzioni globali perché vengono modificati. Le ultime istruzioni della funzione main prevedono di disegnare il canvas con le misure definite all’inizio del programma e poi c’è il main_loop che prende la funzione tick. Viene infine chiamato il main è la funzione parte. 12.11. PROGRAMMAZIONE IN PYTHON – relazioni Gli oggetti diventano molto importanti quando si riescono a comporre insieme. Due o più oggetti possono essere messi insieme se hanno un’ INTERFACCIA COMPATIBILE. Tutto ciò che è stato visto finora era utile quando si aveva un solo oggetto (per una sola pallina si usavano variabili globali) oppure tanti oggetti tutti uguali (per n palline si è usata la programmazione oggetti con l’ausilio delle liste). Quando si inizia ad avere una serie di oggetti con una base comune ma delle specializzazioni diverse si deve ricorrere ad un’astrazione superiore. In biologia si usa la classificazione e la gerarchia ed è un buon metodo: ogni sottoclasse ha le caratteristiche della classe base ma in più ha delle specializzazioni proprie. Con questo metodo è possibile lavorare a diversi livelli di astrazione. La classe base della classificazione è definita come INTERFACCIA ASTRATTA. L’interfaccia è il fatto che tutti gli oggetti facciano una determinata cosa (ad esempio tutti gli animali fanno un verso) mentre il polimorfismo è il fatto che ogni oggetto fa quella determinata cosa in modo diverso (ad esempio ogni animale fa un verso diverso). In Python, data una classe, è possibile creare una serie di sottoclassi tramite la sintassi: class Nome(nome della classe base): e definirne i metodi. Quando si creano delle sottoclassi è implicito il fatto che le nuove classi create abbiano le stesse caratteristiche della classe base. ESEMPIO: si consideri la classe Animal all’interno della quale si definite il metodo speak. Se si considera solo questa classe c’è un’astrazione troppo generale: non è possibile definire un unico verso per la categoria “animali”. Viene infatti inserito l’elemento di controllo dell’errore raise. Dopo aver definito la classe è possibile definire una serie di sottoclassi corrispondenti agli animali: ogni sottoclasse ha la sintassi propria delle sottoclassi di Python e contiene il metodo init che prende in ingresso il parametro self e name. Il campo name prevede di specificare il nome dell’animale. La sottoclasse contiene anche il metodo speak che stampa una stringa contenente il nome dell’animale e il suo verso. Dopo aver definito le classi e le sottoclassi si possono “creare degli animali” tramite l’assegnazione di una variabile ad ogni oggetto: un cane, un gatto e due maiali. È poi possibile creare una lista di animali (i parametri sono le variabili) dove, tramite un ciclo for, per ogni elemento della lista si esegue speak ovvero si stampa il nome e il corrispondente verso. Gli animali sono tutti oggetti diversi che hanno in comune la caratteristica del metodo speak. È quindi possibile gestire oggetti diversi che hanno la stessa interfaccia: animali diversi con la caratteristica comune di avere un verso. ESEMPIO: si considerino una serie di personaggi che hanno tutti la peculiarità di muoversi ma ognuno si muove in un modo diverso rispetto agli altri. La classe base ovvero l’interfaccia astratta è la classe Actor che al suo interno ha il metodo move, pos che restituisce la posizione dell’attore, size che restituisce la dimensione dell’attore e sprite. I valori “attori” sono delle sottoclassi dell’interfaccia astratta Actor e realizzano i metodi
di Actor definendo i comportamenti specifici e poi, se necessario, definiscono ulteriori metodi. Si può quindi creare una sottoclasse Ball che faccia muovere la pallina (o eventualmente più palline) e anche altre sottoclassi: Ghost, Turtle. Tutti questi personaggi che vengono creati hanno la capacità di muoversi, ognuno a modo suo. La cosa importante è avere il metodo move. 14.11. PROGRAMMAZIONE IN PYTHON – sequenze Le liste sono sequenze mutabili di elementi omogenei. A volte è necessario avere una lista con una dimensione nota e i cui valori vengano calcolati durante l’esecuzione. Per fare questo procedimento si usa la LIST REPETITION ovvero si prende una lista di elementi e la si moltiplica per il numero n: quello che si ottiene è un’altra lista che contiene gli stessi oggetti della prima ma in numero pari ad n. Questo metodo delle list repetition è utile quando n è molto grande per evitare di dover scrivere n volte lo stesso oggetto all’interno di una lista. Nell’esempio viene creata una lista di dodici zero, una lista dove i valori 1, 2, 3 sono presenti quattro volte e una lista in cui i due nomi riportati sono moltiplicati per tre volte. Sulle liste ci sono diverse funzioni: len permette di scoprire quanti elementi sono nella lista, append aggiunge un elemento alla fine, remove toglie un elemento (tutte queste funzioni sono già state trattate). È però possibile accedere ai vari valori della lista tramite il loro INDICE , passandolo tra parentesi. Gli elementi n di una lista sono numerati a partire da 0 fino a n-1: scrivendo il nome della lista e l’indice tra parentesi quadre si può ottenere l’elemento desiderato. Gli indici sono utili anche per fare delle sostituzioni: il metodo append permette di aggiungere un elemento alla fine della lista, se invece si vuole mettere un elemento al posto di un altro mantenendo invariata la dimensione della lista si usano gli indici. Gli indici prendono valori da 0 a n-1 e possono essere scritti in ordine crescente oppure in ordine decrescente: se si scrive n-3 o semplicemente - 3 si considera il terzultimo elemento della lista. Non è però possibile andare indietro a piacere, il limite è n. ESEMPIO: si consideri una lista composta dai dodici mesi dell’anno allora n = 12. Se chiedo al programma months[3] ciò che si ottiene non è il mese numero tre ma il terzo elemento della lista, considerando che il primo indice è 0: si ottiene aprile. Se si scrive months[12-3] o semplicemente months[-3] si ottiene ottobre: si deve fare 12 - 3 = 9 e il nono elemento della lista è appunto ottobre (non è il nono mese dell’anno). Se voglio sostituire il mese di novembre con la stringa ‘ mese del mio compleanno’ posso usare l’indice corrispondente a novembre ovvero 10. L’operazione che si svolge è una sostituzione, la dimensione della lista rimane invariata, n è sempre uguale a 12. È possibile prendere delle SLICE della lista ovvero delle porzioni. Per procedere alla creazione di slice si deve indicare l’indice di partenza e l’indice di arrivo all’interno di parentesi quadre e separarsi da :. Quando si considerano le slice, l’indice di fine indicato è escluso. Se si considera la lista dei mesi del precedente esempio, la slice months[2:5] restituisce tre valori (5-2 = 3) e sono i mesi corrispondenti agli indici 2, 3, 4: marzo, aprile, maggio. È possibile anche omettere uno degli indici o entrambi:
ESEMPIO: vengono riportati due esempi che comprendono al loro interno una lista. I due esempi sono apparentemente uguali ma, in realtà, restituiscono due risultati completamente diversi. Caso 1: la funzione reset prende data, la lista in ingresso, e ne esegue la funzione crea ovvero toglie tutti gli elementi della lista. Se nella funzione main si prende la lista nums e, su questa lista, si chiama la funzione reset, ciò che si ottiene è una lista vuota. La lista nums prende il posto della lista data e, su di essa, viene svolta la funzione clear, propria della funzione reset. Caso 2: la funzione reset prende data come lista in ingresso e determina che data sia pari ad una lista vuota. La funzione main prende la lista nums e su questa lista chiama la funzione reset. Ciò che si ottiene è una lista che contiene i valori 1,2,3. Siccome nella funzione di partenza reset non ci sono funzioni interne, viene solo definito che data sia una lista vuota, quando si chiama la funzione non viene eseguito nulla su nums che rimane infatti invariata. Le STRINGHE possono essere usate in modo analogo alle liste poiché sono sequenze immutabili di caratteri. Ogni lettera della stringa può essere indicata con un indice e quindi valgono le stesse proprietà viste per le liste: i valori partono dall’indice 0 fino a n-1. Anche sulle liste è possibile fare le slice, ciò che non si può fare è l’assegnamento perché le stringhe sono sequenze immutabili. È però possibile fare le concatenazioni e creare nuove stringe da quelle di partenza. È possibile avere una lista di stringhe. Se si vuole concatenare insieme le stringhe di una lista, si può usare il metodo join. La sintassi di join prevede di mettere una stringa di partenza che è il separatore (se non si vuole nessun separatore si mette la stringa vuota oppure la stringa vuota con uno spazio in mezzo) e poi, tra parentesi viene chiamata la lista. È anche possibile fare l’operazione inversa ovvero, date delle stringhe con un separatore, è possibile dividere questi elementi e creare una lista di stringhe tramite il metodo split. La sintassi di split prevede di mettere la lista di elementi, il punto, chiamare la funzione split e mettere tra parentesi la stringa separatrice. Le TUPLE possono essere usate in modo analogo alle liste poiché sono sequenze immutabili di valori anche di tipo diverso. Anche sulle tuple è possibile utilizzare gli indici ma è una metodologia sconsigliata poiché, essendo la tupla una sequenza di valori di tipo diverso, non è detto che questi valori siano omogenei e quindi potrebbero avere significati diversi. Sulle tuple è meglio fare l’ unpacking ovvero lo spacchettamento tramite l’assegnazione di variabili spieganti il significato dei vari elementi della tupla. L’unpacking si può fare su qualunque sequenza: tuple, liste, stringhe. L’unico limite dell’unpacking è che la lunghezza dello spacchettamento e quindi delle variabili scelte coincida con gli oggetti che effettivamente si stanno trattando. L’operazione inversa dell’unpacking è il packing ovvero il “pacchettamento”: date delle variabili che si riferiscono a dei valori, le si possono mettere insieme tramite tupla, lista o stringa a seconda di ciò che si vuole ottenere. Il limite è sempre che le lunghezze coincidano. Le liste sono utili come collezioni di oggetti ognuno dei quali ha una determinata posizione e un elemento della lista può comparire al suo interno anche più volte. L’ INSIEME è invece una collezione non ordinata di oggetti senza ripetizioni. Per creare un insieme si utilizzano le parentesi graffe al cui interno sono posti i valori. Si può controllare la presenza di un elemento nell’insieme tramite la funzione in ma non è possibile sapere la posizione di quel dato elemento, non ci sono gli indici negli insiemi. In controlla quindi l’appartenenza, si può aggiungere qualcosa all’insieme tramite l’operazione add e si può togliere qualche valore dall’insieme tramite l’operazione discard. Se si tenta di togliere dall’insieme un
valore che non è presente, il programma non restituisce errore ma è comunque bene controllare prima se l’elemento da manovrare è presente nell’insieme. Sugli insiemi si possono fare le operazioni proprie dell’insieme matematico: