Sei sulla pagina 1di 25

Lezione 31.3.22 - 7.4.22 - 11.4.

22

Orario:
2 pause da 15 minuti
9.00 - 10.00
10.15 - 11.15
11.30 - 12.30

Per contattare:
niki.martinel@uniud.it
oggetto: [LPSM-2021]
Ricevimento: Tutti lunedì 9.30 -10.30, questo è l’orario è durante la lezione bisogna mandare e-mail
e ci si accorda.

Programma:
- Linguaggi di programmazione attraverso Python e le sue funzionalità di base.
- Comprendere la notazione per l’accesso agli elementi di un vettore NumPy
- Elaborare una stringa allo stesso modo in cui si processa un vettore di numeri

Pacchetto in cui c’è anche Python e saperli usare e capire

Python è un linguaggio di programmazione che ci aiuta ad affrontare i problemi in modo flessibile.


Manipolare le informazioni contenute e far capire al computer di eseguire quella determinata
azione, questo avviene tramite anche un programma.

Cosa vuol dire programmare? Vado a dire al pc le regole che deve seguire per svolgere l’azione,
istruire il pc per eseguire le mie richieste/ esigenze del momento.
Il programma avendo dato l’input che abbiamo, svolgerà un output che ti permette di eseguire la
richiesta.
Un qualcosa che si può usare per svolgere un determinato compito con il computer.

Riesca a produrre qualcosa di sensato nell’input e svolgere qualcosa di sensato e di utilizzabile


nell’output.

Linguaggio di programmazione= ogni programma ha una sintassi diversa (regole proprie del
linguaggio di programmazione che vanno rispettate, quando noi andiamo a usate quel programma).
Un modo di tradurre la logica umana in istruzioni comprensibili per il computer come i linguaggi
umani, esistono moltissimi linguaggi (spesso simili, spesso differenti tra loro), ciascuno con uno
specifico set di regole (sintassi, grammatica) da seguire

Codice= Un set di comandi specifici per un dato linguaggio di programmazione. Un programma


consiste in pezzi di codice messi assieme seguendo una certa logica usando codice di alter persone,
si può incorporare parte del programma scritto da altri nel proprio!

Cos’è Python? È un linguaggio di programmazione: interpretato, di alto livello, semplice da imparare


e usare, potente e produttivo, ottimo anche come primo linguaggio (molto simile allo
pseudocodice). Inoltre è open source (www.python.org), è multipiattaforma è facilmente
integrabile con C/C++ e Java

Puo essere usato sia per windows che per mac.

Ci sono due tipi di linguaggi:


- Interpretato: man mano che le istruzioni vengono scritte, vengono eseguite e capite
direttamente dalla macchina.
- Compilati: tra programma scrivente e il programma risultante, c’è lo step di compilazione in
mezzo, ovvero un programma di compilazione che traduce il programma alla macchina.

È usato dalla nasa, da google, facebook, amazon,…, industrial light magic ( quelli che fanno effetti
speciali per star wars), ecc…

Dove e come?
à esercitarsi
• Python dispone di un interprete interattivo molto comodo e potente che può essere usato
direttamente dalla shell dei comandi
• Come già visto nelle precedenti lezioni noi utilizzeremo Google Colab ( IPython) portale e-learning
( ti porta in un ambiente che andremo a fare i compitini, ma lo possiamo usare anche per esercirarci
)
• Visualizzare «come funziona» uno script, capire linea per linea quello che sta facendo.
• Capire come le variabili sono usate e modificate

https://pythontutor.com/

L’interprete
• I file sorgente Python sono file di testo, generalmente con estensione “.py ”
• Le istruzioni sono separate dal fine riga e non da “ ; ”
• Per far continuare un’istruzione anche sulla linea successiva è necessario inserire un “\” a fine riga
• Se le parentesi non sono state chiuse correttamente Python capisce che l’istruzione si estende
anche sulla riga successiva

Hello World
• L’istruzione “print” stampa il suo argomento trasformandolo in una stringa
>>> print(5)
5
>>> print("Hello world")*
Hello world
*Il nome della funzione, aperta parentesi, nome della stringa e chiusa patentesi.
Python basics
I numeri
• I numeri vengono definiti in questo modo:
• 42 (intero, decimale)
• 0x2A (intero, esadecimale) à forma esadecimale
• 0.15 (floating point, formato normale)
• 1.7e2 (floating point, formato esponenziale)
• Lo “0” iniziale o finale può essere omesso:
• “.5” è “0.5”
• “5.” è “5.0”

• Gli interi, se necessario, sono automaticamente convertiti in long


• 2 ** 64 → 18446744073709551616L
à Doppio asterico (**) si intende l’elevazione (potenza)

Gli Operatori Matematici


• Esistono gli stessi operatori del C, le parentesi possono essere usate per raggruppare:
>>> (5 + 3) * 2 16

• Esiste anche l’operatore elevamento a potenza “**”:


>>> 5 ** 2 25
• Esiste anche la percentuale per il resto come in JavaScript
• Non esistono “++” e “--”

Conversione fra Tipi Numerici: rappresentare il numero del dato in stringa


• Esistono alcune utili funzioni di conversione fra i numeri:
• int(x[, base]) ritorna x convertito in intero, prendere un dato oggetto, che può essere un
numero o una stringa, e questa funzione mi traduce il numero in una rappresentazione
decimale.
• base è la base in cui x è rappresentato (il valore di default è 10) : es. io scrivo ‘13’ e lui
capisce che è numero anche se è sotto forma di stringa.
• int("13") → 13
• int("13", 8) → 11
• int("xxx") → Errore!

• long(x[, base]) come “int” ma ritorna un “long”

• float(x) ritorna x convertito in floating point : es. io scrivo ‘13.2’ e lui capisce che è numero
anche se è sotto forma di stringa.
• float("13.2") → 13.2
• float(42) → 42.0

Variabili: Parole chiavi che tramite codice usiamo per contenere delle informazioni.
• I nomi di variabili sono composti da lettere, numeri e underscore, il primo carattere non può
essere un numero (come in C)
• Sono validi:
• x, ciao, x13, x1_y, _, _ciao12
• Non sono validi:
• 1x, x-y, $a, àñÿô (inizia con un numero o anche il carattere, per questo non è
valido)

• Le variabili non devono essere dichiarate (Tipizzazione dinamica), ovvero posso usare le variabili
assegnandole i dati senza specificare il tipo di dato che deve essere contenuto in quella variabile

• Una variabile non può essere utilizzata prima che le venga assegnato un valore

Assegnazione
• L’assegnazione avviene attraverso l’operatore = (X contiene quel numero, ovvero si va ad
assegnare a x quel numero)

• Esempio:
>>> x = [0, 1, 2]
>>> y = x
>>> x.append(3)
>>> print y [0, 1, 2, 3]

Esempi:
• >>> x=5
• >>> nome = ‘Marco’
• Sintetico
• >>> inizio, fine = 2, 100

• type restituisce il tipo di una variabile


>>> x = [5, 3]
>>> type(x)
>>> <type ‘list’>
x è di tipo lista (verrà vista nel dettaglio più avanti)

VERO E FALSO:
In Python esistono due variabili di tipo booleano:
True uguale a 1 e False uguale a 0

• Per i tipi predefiniti sono considerati falsi:


• Il numero 0 o 0.0
• Una stringa vuota (“”)
• {}, [], ()

• Gli altri valori sono considerati True, numero diverso da zero, striga al cui interno c’è assegnato
qualcosa

Gli Operatori di Confronto: Due oggetti rappresentano la stessa informazione/ contenuto.


• Sono:
• 1 == 3 → Falso
• 1 == 2 - 1 → Vero viene eseguito la sottrazione
• 1 != 2 → Vero diseguaglianza (!= diverso da)
• 1 < 2 → Vero
• 1 > 3 → Falso
• 1 >= 1 → Vero

• Se necessario vengono eseguite le necessarie conversioni intero → virgola mobile


• 1 == 1.0 → Vero

Operatori booleani: ci permette di mettere più condizioni tra loro,


• not x à False se x è vero, True se è falso (operatore di negazione, nega e inverte il nome della
variabile), nega e inverte x,

• x and y à True se x e y sono entrambi True. Restituisce:


• Se x è False lo ritorna
• Altrimenti ritorna y
• 1 and 5 → 5 → Vero
• [] and 1 → [] → Falso

And: si comporta il risultato dell’operatore ha due variabili (x,y),


andà stabilisce la condizione il risultato restituisce il risultato ero se le due variabili sono entrambe
vere. Se uno dei due (o x o y), sono false, l’operatore restituisce false

• x or y à True se almeno uno degli argomenti è True


• Se x è vero lo restituisce
• Altrimenti restituisce y
• 1 or 0 → 1 → Vero
• () or 0 → 0 → Falso

Or: restituisce il true se almeno uno delle due variabili è vera.

• Sia and sia or utilizzano la logica del corto circuito


• Il secondo argomento non viene valutato se il risultato dell’operazione è già noto in base al
solo primo argomento

None: è una variabile molto importante con lo stesso ruolo di null in C


- In C null è uguale a 0
o Rischio di confusione
- In Python NONE è di tipo non numerico
o Non vi è rischio di confusione con altri tipi

Input e Output
• Si può formattare l’output in questo modo:
• >>> x=18; y=15
• >>> print(‘x={} y={}’.format(x,y))
x=18 y=15
ho una stringa apice x e y un .format alla stringa che mi precede e sostituisci in ordine i valori
di x e y

• Per leggere un dato si usa input()


• >>> x=input (‘Scrivi un numero:’) à assegna a x il numero.
• >>> x=input (‘Scrivi il tuo nome:’) à assegna a x il nome.

>>> x=18
>>> y=15
>>> ‘x è uguale a (), y è uguale a ()’
‘x è uguale a (), y è uguale a ()’
>>> ‘x è uguale a (), y è uguale a ()’ .format (x,y) à oggetto stringa, per questo metto gli
apici
‘x è uguale a 18, y è uguale a 15’
>>> print (‘x è uguale a (), y è uguale a ()’ .format (x,y)) à mi stampa il risultato
x è uguale a 18, y è uguale a 15

strutture dati: rappresentazioni interne, tale che io li uso per contente le informazioni diverse
Ci sono tre topi di strutture dati:
- Liste
- Trupe
- Dizionari

Liste: oggetti definite attraverso l’utilizzo dei dati


•Contengono elementi anche eterogenei
• Per creare una lista si usano le parentesi quadre, gli elementi sono delimitati da virgole
>>> [1, 2, "ciao"]
[1, 2, 'ciao']

• Stessi operatori delle stringhe ma sono mutabili


• [1] + [3, 6] → [1, 3, 6]

• [1, 0] * 3 → [1, 0, 1, 0, 1, 0] lista moltiplica o replica il contenuto n volte

• [2, 3, 7, 8][1:3] → [3, 7] selezionare sotto elementi della lista


Oggetto lista se a destra ho un’altra parentesi e chiusa parentesi, che sono delle procedure
che io uso per accedere alla lista che sta alla sinistra. Dalla lista che mi precede prendi solo
quelli elementi.
Estrarre contenuti della lista in una precisa posizione.
>>>[2,3,5,8] [0]
2
>>> [2,3,5,8] [2]
5
>>> [2, 3, 7, 8][1:3] → [3, 7]
[1:3] à posizione uno e tre
>>> [2, 3, 7, 8][10]
Underfine perché non è possibile estrarre quel numero.

>>> [2,3,5,7] [-1]


** 7 à ha inserito una funzione se io metto il meno prima dell’indice che io voglio estrarre,
conta dall’ultimo elemento della lista, in questo caso il 7.
Con il -n comincio a contare ultimo elemento della lista a partire dalla posizione 1 e non da
zero.
>>> [2,3,5,7] [-10]
Da errore

Come lo slice in javascript: considera i elemento della sottolista e prende i valori della lista
escluso l’ultimo elemento
>>> [2,3,5,7] [1:4]
[3,5,7]

>>> [2,3,5,7] [1:]


[3,5,7] à Prendi tutti gli elementi dall’indice 1 in poi

>>> [2,3,5,7] [:2]


[2,3] à dalla posizione 2 in poi ( mi sposto da dx a sinistra, posizione 2 esclusa)

>>> [2,3,5,7] [:]


[2,3,5,7] àprende tutta la lista

>>> [2,3,5,7] [:10]


[2,3,5,7] àprende tutta la lista

>>> [2,3,5,7] [:-1]


[2,3,5] àprende tutta la lista eccetto il 7 **

• [2, 3, 7, 8][:2] → [2, 3]

• [1, 2, 3][0] = 5 → [5, 2, 3] sostituisce il numero nella posizione zero

LISTE I METODI
Alcuni tra i metodi più comunemente usati:
• L.append(obj), aggiunge obj in fondo ad L à procedure che prendono una serie di valori e
vanno a modificare con il contenuto dell’oggetto su cui io sto chiamando l’esecuzione della
funzione ( a distanza L vado ad interagire con il suo contenuto)
Aggiunge un oggetto che è un numero, nome, ecc.., alla fine

• L.extend(list), aggiunge in fondo ad L gli elementi di list


Aggiunge un oggetto che è una lista, e lo mette in fondo alla lista iniziale

• L.insert(index, obj), aggiunge “obj” prima di “index”


Aggiunge un elemento
• L.pop([index]), rimuove l’elemento in posizione index e lo ritorna, il valore di default di
index è -1
Rimuove un elemento

• L.remove(value), cancella la prima occorrenza di value


Toglie il primo elemento che specifico a va cercare l’elemento

• L.reverse(), inverte la lista

• L.sort(), ordina la lista

• Tutti “in place”! Viene modificata la lista, non viene ritornata una nuova lista
• Attenzione: l’operatore + rispetto ad append crea una nuova lista (es. slide precedente)

TUPLE: simile alle liste, ma invece di usare le parentesi quadrate usano le parentesi tonde. Sono
oggetti, che io non posso modificare, quando finisco un tupla, il contenuto non lo posso più
modificare.
Possono omettere le parentesi tonde.

• Delimitate da parentesi, gli elementi sono separati da virgole


• (1, 2, 3)
• (1,) # un solo elemento
• () # nessun elemento

• Simili alle liste ma immutabili


• (1, 2)[0] = 5 → Errore!

• Le parentesi possono essere omesse se non si creano ambiguità


• Sono equivalenti
• variabile = 5, 2, 3
• variabile = (5, 2, 3)

DIZIONARI: usano le parentesi graffe. Sono definititi attraverso chiave:valore


(oggetto (stringa): valore (qualsiasi cosa))
• Associano ad una chiave un valore

• Creati nella forma {chiave1: val1, chiave2: val2},


Es:
• {"nome": "Mario", "cognome": "Rossi"}

• L’accesso e l’inserimento di elementi avviene come per le liste ma al posto dell’indice di posizione
della lista uso la «chiave»
•--"a": 1, "b": 2}["a"] → 1 (à nelle parentesi quadre inserisco la stringa non specificando
l’indice ma specificando la chiave)
• {"a": 1, "b": 2}["X"] → Errore!
• {}["X"] = 2 → {'X': 2} à al dizionario vuoto aggiunge la coppia chiave:valore

• Le chiavi devono essere immutabili

DIZIONARI I METODI:
• Alcuni metodi principali dei dizionari sono:
• D.clear() elimina tutti gli elementi dal dizionario

• D.copy() restituisce una copia di D

• k in D restituisce 1 se k è nel dizionario, 0 altrimenti

• D.items(), D.keys(), D.values() restituiscono rispettivamente:


• Una lista con le tuple (chiave, valore)
• La lista delle chiavi
• La lista dei valori

• D.update(D2) aggiunge le chiavi e valori di D2 in D


• D.get(k, d) restituisce D[k] se la chiave è presente nel dizionario, d altrimenti. Il valore di
default di d è None
Se chiave 10 esiste mi restituisce il valore della chiave 10, ovvero 2. Lo si nota perché ha le ‘
‘.

In Phyton questo simbolo >>> indicatore che mi dice che sto lavorando su quella linea

ASSEGNAZIONE: quello che succede

X+1 mi crea un altro oggetto, e devo guardare solo questo.


Per le liste passa il riferimento, mentre per le ‘variabili’ passa il valore.
ELIMINARE UN ELEMENTO del è una funzione e non usa le parentesi tonde,
es. ho delle variabili x con del contenuto, e voglio eliminarla del tutto, ma devo usare questo
comando (del) affiancata dalla funzione.
elimina variabili, ma anche elementi all’interno della lista

• L’istruzione del ha due usi differenti

• del x cancella la variabile x, cioè non si potrà più usare x senza averle prima assegnato un nuovo
valore

• del seq[ind] cancella l’elemento con indice/chiave ind da seq


>>> li = [1, 2, 3]
>>> del li[1] → li = [1, 3]

>>> d = {"a": 1, "b": 6}


>>> del d["a"] → d = {'b': 6}

>>> l2 = [1, 2, 3, 4]
>>> del l2[1:3] → l2 = [1, 4]
ALTRI OPERATORI DI CONTROLLO IS e IN
• in, vero se il primo operando è contenuto nel secondo
• 5 in [1, 2, 3] → Falso
Bisogna vedere se il 5 sia contenuto nella lista.
• 2 in [1, 2, 3] → Vero
• "a" in {"x": 1, "a": 2} → Vero
• "a" in "ciao" → Vero

Mi restituisce un valore vero o falso, e indica se l’oggetto contenuto a sinistra dell’in sia contenuto
dell’oggetto a destra dell’in

Nei dizionari bisogna vedere se l’elemento è una chiave


Nelle stringhe l’elemento è contenuto nella stringa a destra.

• is, vero se il primo operando è il secondo (non solo è uguale!)


• Attualmente implementato come confronto fra le posizioni in memoria degli operandi
(id(x) restituisce l’indirizzo di memoria)
• Usato al posto di == per il confronto con None
CONDIZIONE IF
• La sintassi di if è:
if condizione principale :
...
elif condizione_alternativa:
...
else:
...
Se succede qualcosa allora eseguo l’operazione, x=[ …
In tutte le e tre le sintassi uso i due punti (:), per evidenziare a condizione
Deve essere allineato in modo specifico, ovvero tabulato, che sposta il mio codice verso destra.

• Sia la parte elif sia la parte else sono facoltative

• Può esserci un numero qualsiasi di elif

• Non sono necessarie le parentesi per racchiudere l’espressione booleana

• Non sono possibili assegnazioni all’interno della condizione


INDENTAZIONE
• Il raggruppamento è definito dall’indentazione
• Non si usano parentesi graffe, coppie “begin”/“end” e simili
• Obbliga a scrivere codice ordinato
• Più naturale, evita i tipici problemi del C, come ad esempio: if (0) printf("Questo non viene
eseguito"); printf("Questo sì");
• Si possono usare spazi o tabulazioni

PASS
• Come tradurre il seguente codice in Python?
if (a){} /* Oppure "if (a);" */ b = 12;
• In Python dopo un if deve esserci un blocco indentato if a: b = 12 # Dovrebbe essere indentato!
• Si usa quindi l’istruzione pass che non ha nessun effetto if a: pass # Non fa nulla b = 12

FUNZIONI BUILT – IN
• range([start,] end[, step]) restituisce una lista contenente gli interi in [start, end).
• step è l’incremento, il valore di default è “+1”.
• Il valore di default di start è “0”
• Molto usato con i cicli “for”
• for i in range(5): print(i)
• len(seq) ritorna il numero di elementi in seq
• len("ciao") → 4
• len("x\0x") → 3 ( lo slash è un carattere speciale e non viene contato)
• len([1, 2, 3]) → 3 (contati gli elementi all’interno della lista )
• len({"a": 1, "b": 5}) → 2 (vengono contate le coppie)
CICLI WHILE ripete infinite volte il ciclo
• La sintassi è:
while condizione:
...
while i < 10

• Si può uscire dal ciclo usando break (comando che fa si che il primo ciclo superiore dove trova
all’interno questa parola, viene interrotto)

• Si può passare all’iterazione successiva usando continue (istruzione, che obbliga il programma a
rivalutare il ciclo). Nel momento in cui raggiungo quel comando …
• Esempio:
while 1:
# significa ciclo infinito
if condizione1:
continue (con il continue le prossime due funzioni non vengono
considerate, perché si ferma alla prima condizi)
if condizione2:
break
print(42)
1 foto

CICLO FOR
• La sintassi è:
for variabile in iterator:
...

• iterator può essere:


• Una sequenza:
• Liste
• Tuple
• Stringhe
• Dizionari
• Classi definite dall’utente
• Un iteratore (che vedremo poi)

Si possono usare continue e break come per il while.

ESEMPI:

Mi stampa il contenuto dello studente, per ciascun elemento nella lista student, stampo solo quella,
in ordine come è scritto nella lista.
Se io volessi sommare i valori con 10. Definisco la variabile sum( che equivale a 0), dove per ogni x
(ha un range con un valore incluso à 1, e un valore escluso à 11), si ha sum che viene sommato a
x.

Tre apice sopra e tre apici sotto indica il COMMENTO. (‘’’)

Esempio for:

Vedere altri esempi (students)


Per correggerlo:

Il -1 è riferito alla posizione

Versione breve
Valori:
- Start: len(valori)
- Stop: -1

OPZIONI (corrette al momento):


1.

ESERCIZIO:
NAMES = [ Al, Bob, Carl, Dylan, Elon]
Names[0] Names[1] Names[2] Names[3] Names[4]
LE STRINGHE
• Le stringhe sono racchiuse fra apici singoli o doppi
>>> 'Python’
'Python'

>>> print("Ciao\mondo")
'Ciao'
'mondo’

• Si possono usare alcuni operatori visti per i numeri (* moltiplica il contenuto)


>>> "ciao " + "mondo" # concatenazione 'ciao mondo'

>>> "ABC" * 3 # ripetizione


'ABCABCABC'

ALTRI TIPI DI STRINGA


• Le stringhe possono estendersi su più righe, in questo caso sono delimitate da tre apici singoli o
doppi
"""Questa è una stringa su più righe"""

• For e stringhe
nome=”Gianluigi”
for c in nome:
print(c)
STR E REPR
• str(x) ritorna x convertito in stringa

• repr(x) ritorna una stringa che rappresenta x, normalmente più vicino a ciò che “x” è realmente
ma meno “bello” di ciò che è ritornato da “str”
print("ciao\n\tmondo») → ciao
mondo print(repr("ciao\n\tmondo")) → 'ciao\n\tmondo'
print(ogg) → Questo è un oggetto
print(repr(ogg)) → < class C at 0x008A6570 >

• print applica str automaticamente al suo argomento


METODI
• S.split([sep[, max]]) ritorna una lista contenente le parti di S divise usando i caratteri di sep come
separatore. max è il numero massimo di divisioni eseguite. Il valore di default di sep è uno spazio
bianco

• S.join(seq) ritorna una stringa contenente gli elementi di seq uniti usando S come delimitatore

• S.lower() ritorna S convertito in minuscolo

• S.upper() ritorna S convertito in maiuscolo

• S.find(what[, start[, end]]) ritorna il primo indice di what in S[start, end]. Se la sottostirnga non è
trovata ritorna -1

• S.rfind(what[, start[, end]]) come find ma a partire dal fondo

• S.replace(old, new[, max]) ritorna una copia di S con max occorrenze di old sostituite con new. Il
valore di default di max è tutte.

• S.strip() restituisce una copia di S senza gli spazi iniziali e finali

• S.lstrip(), S.rstrip() come “strip” ma eliminano rispettivamente solo gli spazi iniziali e finali

FORMATTAZIONE: sostituire quello che prima è passata alla funzione, rimpiazzando il valore tra le
parentesi graffe
• La funzione S.format() serve per formattare le stringhe
• S.format(valori)

• Le stringhe di formattazione sono le stesse usate dal C


• ‘-{:s}-’.format(‘x’) → -x-
• ‘{:s}{:d}’.format(‘x', 12) → x12
FUNZIONI: gruppo di istruzioni, che condiziona il contenuto stesso.
• La sintassi è:
def funzione(arg1, arg2, opz1=val1, opz2=val2):
...

Parametri obbligatori vengono inseriti nei paragrafi opzionali (assegno un valore di default), e lo
specifica in questo modo:
opz1=val1

• Non bisogna specificare il tipo restituito


• Gli argomenti sono normali variabili e possono essere in qualsiasi numero
• Se la funzione non accetta argomenti basta usare una lista di argomenti vuota [metto le
parentesi tonde senza contenuto all’interno, ()], ad esempio: def foo():
...

• Gli argomenti opzionali possono non essere specificati dal chiamante, in questo caso assumono il
valore di default

• Le variabili all’interno della funzione non sono visibili dall’esterno

• Esempio di utilizzo di una funzione:


>>> def foo(x, y, z=42, k=12):
... print(x, y, z, k)
...
>>> foo(5, 3, k=9)
5 3 42 9

Arg 1 e Arg 2 DEVONO ESSERE SEMPRE SPECIFICATI!!!

Potrebbero piacerti anche