3. Un'introduzione informale a Python
*************************************

Nei seguenti esempi, input e output si distinguono per la presenza o
meno del prompt (*>>>* e *...*): per ripetere l'esempio, è necessario
digitare tutto dopo il prompt, quando questo è presente; le righe che
non iniziano con un prompt vengono emesse dall'interprete. Si noti che
un prompt secondario su una linea da solo in un esempio significa che
è necessario digitare una riga vuota; questo viene utilizzato per
terminare un comando a più righe.

Molti degli esempi di questo manuale, anche quelli inseriti al prompt
interattivo, includono commenti.  I commenti in Python iniziano con il
carattere *hash*, "#", e si estendono fino alla fine della riga.  Un
commento può apparire all'inizio di una riga o dopo uno spazio bianco
o codice, ma non all'interno di una stringa.  Un carattere hash
all'interno di una stringa letterale è solo un carattere. Poiché i
commenti servono solo a chiarire il codice e non sono interpretati da
Python, possono essere omessi quando si scrivono gli esempi.

Alcuni esempi:

   # this is the first comment
   spam = 1  # and this is the second comment
             # ... and now a third!
   text = "# This is not a comment because it's inside quotes."


3.1. Usare Python come calcolatrice
===================================

Proviamo con alcuni semplici comandi di Python.  Avviare l'interprete
e attendere il prompt primario, ">>>".  (Non dovrebbe volerci molto.)


3.1.1. Numeri
-------------

L'interprete agisce come una semplice calcolatrice: è possibile
digitare un'espressione per scrivere il valore.  La sintassi
dell'espressione è semplice: gli operatori "+", "-", "*" e "/"
funzionano come nella maggior parte degli altri linguaggi (per
esempio, Pascal o C); le parentesi ("()") possono essere utilizzate
per il raggruppamento. Per esempio:

   >>> 2 + 2
   4
   >>> 50 - 5*6
   20
   >>> (50 - 5*6) / 4
   5.0
   >>> 8 / 5  # division always returns a floating-point number
   1.6

I numeri interi (es. "2", "4", "20") hanno tipo "int", quelli in
virgola mobile (es. "5.0", "1.6") hanno tipo "float".  Torneremo a
parlare ancora dei tipi numerici più avanti nel tutorial.

La divisione ("/") restituisce sempre un float.  Per fare *floor
division* e ottenere un risultato intero (scartando qualsiasi cifra
decimale) si può usare l'operatore "//"; per calcolare il resto si può
usare "%":

   >>> 17 / 3  # classic division returns a float
   5.666666666666667
   >>>
   >>> 17 // 3  # floor division discards the fractional part
   5
   >>> 17 % 3  # the % operator returns the remainder of the division
   2
   >>> 5 * 3 + 2  # floored quotient * divisor + remainder
   17

Con Python, è possibile utilizzare l'operatore "**" per calcolare le
potenze [1]:

   >>> 5 ** 2  # 5 squared
   25
   >>> 2 ** 7  # 2 to the power of 7
   128

Il segno uguale ("=") è usato per assegnare un valore ad una
variabile. Successivamente, nessun risultato viene visualizzato prima
della successiva richiesta:

   >>> width = 20
   >>> height = 5 * 9
   >>> width * height
   900

Se una variabile non è stata ”definita" (a cui è stato assegnato un
valore), usarla vi darà un errore:

   >>> n  # try to access an undefined variable
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   NameError: name 'n' is not defined

C'è pieno supporto per i numeri in virgola mobile; gli operatori con
operandi di tipo misto convertono l'intero in un numero in virgola
mobile:

   >>> 4 * 3.75 - 1
   14.0

In modalità interattiva, l'ultima espressione stampata viene assegnata
alla variabile "_".  Questo significa che quando si utilizza Python
come calcolatrice da tavolo, è un po' più facile continuare i calcoli,
ad esempio:

   >>> tax = 12.5 / 100
   >>> price = 100.50
   >>> price * tax
   12.5625
   >>> price + _
   113.0625
   >>> round(_, 2)
   113.06

Questa variabile deve essere trattata dall'utente in sola lettura.
Non va assegnato esplicitamente un valore ad essa --- si dovrebbe
invece creare una variabile locale indipendente con lo stesso nome,
mascherando così la variabile *built-in* e il suo comportamento
magico.

Oltre a "int" e "float", Python supporta altri tipi di numeri, come
"Decimal" e "Fraction". Python ha anche il supporto incorporato per
complex numbers, e usa il suffisso "j" o "J" per indicare la parte
immaginaria (es. "3+5j").


3.1.2. Testo
------------

Python può manipolare testo (rappresentato dal tipo "str", le
cosiddette "stringhe") così come numeri. Questo include caratteri
""!"", parole ""rabbit"", nomi ""Paris"", frasi ""Got your back."",
ecc. ""Yay! :)"". Possono essere racchiusi tra virgolette singole
("'...'") o virgolette doppie (""..."") con lo stesso risultato [2].

>>> 'spam eggs'  # single quotes
'spam eggs'
>>> "Paris rabbit got your back :)! Yay!"  # double quotes
'Paris rabbit got your back :)! Yay!'
>>> '1975'  # digits and numerals enclosed in quotes are also strings
'1975'

racchiudere una virgoletta dello stesso tipo, dobbiamo farne
l'"escape", precedendola con "\". In alternativa, possiamo usare
l'altro tipo di virgolette:

   >>> 'doesn\'t'  # use \' to escape the single quote...
   "doesn't"
   >>> "doesn't"  # ...or use double quotes instead
   "doesn't"
   >>> '"Yes," they said.'
   '"Yes," they said.'
   >>> "\"Yes,\" they said."
   '"Yes," they said.'
   >>> '"Isn\'t," they said.'
   '"Isn\'t," they said.'

Nella shell di Python, la definizione di una stringa e la stringa di
output possono apparire differenti. La funzione "print()" produce un
output più leggibile, omettendo le virgolette di chiusura e stampando
i caratteri con escape e speciali:

   >>> s = 'First line.\nSecond line.'  # \n means newline
   >>> s  # without print(), special characters are included in the string
   'First line.\nSecond line.'
   >>> print(s)  # with print(), special characters are interpreted, so \n produces new line
   First line.
   Second line.

Se non si desidera che i caratteri preceduti da "\" siano interpretati
come caratteri speciali, è possibile utilizzare le cosiddette *raw
strings* aggiungendo un "r" prima del primo apice:

   >>> print('C:\some\name')  # here \n means newline!
   C:\some
   ame
   >>> print(r'C:\some\name')  # note the r before the quote
   C:\some\name

C'è un aspetto sottile nelle stringhe raw: una stringa raw non può
terminare con un numero dispari di caratteri "\"; vedi la voce FAQ per
ulteriori informazioni e soluzioni.

String literals can span multiple lines.  One way is using triple-
quotes: """"..."""" or "'''...'''".  End-of-line characters are
automatically included in the string, but it's possible to prevent
this by adding a "\" at the end of the line.  In the following
example, the initial newline is not included:

   >>> print("""\
   ... Usage: thingy [OPTIONS]
   ...      -h                        Display this usage message
   ...      -H hostname               Hostname to connect to
   ... """)
   Usage: thingy [OPTIONS]
        -h                        Display this usage message
        -H hostname               Hostname to connect to

   >>>

Le stringhe possono essere concatenate (incollate insieme) con
l'operatore "+" e ripetute con "*":

   >>> # 3 times 'un', followed by 'ium'
   >>> 3 * 'un' + 'ium'
   'unununium'

Due o più *letterali di tipo stringa* (cioè quelli racchiusi tra
virgolette) posizionati uno accanto all'altro sono automaticamente
concatenati.

   >>> 'Py' 'thon'
   'Python'

Questa funzione è particolarmente utile quando si vogliono separare
stringhe lunghe:

   >>> text = ('Put several strings within parentheses '
   ...         'to have them joined together.')
   >>> text
   'Put several strings within parentheses to have them joined together.'

Questo funziona solo con due letterali, ma non con variabili o
*expression*:

   >>> prefix = 'Py'
   >>> prefix 'thon'  # can't concatenate a variable and a string literal
     File "<stdin>", line 1
       prefix 'thon'
              ^^^^^^
   SyntaxError: invalid syntax
   >>> ('un' * 3) 'ium'
     File "<stdin>", line 1
       ('un' * 3) 'ium'
                  ^^^^^
   SyntaxError: invalid syntax

Se volete concatenare variabili o una variabile e un letterale, usate
"+":

   >>> prefix + 'thon'
   'Python'

Le stringhe possono essere *indicizzate* (sottoscritte), e il primo
carattere ha indice 0. Non esiste un tipo carattere specifico; un
carattere è semplicemente una stringa di dimensione uno:

   >>> word = 'Python'
   >>> word[0]  # character in position 0
   'P'
   >>> word[5]  # character in position 5
   'n'

Gli indici possono anche essere numeri negativi, per iniziare a
contare da destra:

   >>> word[-1]  # last character
   'n'
   >>> word[-2]  # second-last character
   'o'
   >>> word[-6]
   'P'

N.B. Poiché -0 è uguale a 0, gli indici negativi partono da -1.

Oltre all'indicizzazione, è supportato anche lo *slicing*.  Mentre
l'indicizzazione è usata per ottenere i singoli caratteri, lo
*slicing* permette di ottenere una sottostringa:

   >>> word[0:2]  # characters from position 0 (included) to 2 (excluded)
   'Py'
   >>> word[2:5]  # characters from position 2 (included) to 5 (excluded)
   'tho'

Nello slice gli indici hanno degli utili valori predefiniti; un primo
indice omesso è zero, un secondo indice omesso è uguale alla
dimensione della stringa che si sta tagliando:

   >>> word[:2]   # character from the beginning to position 2 (excluded)
   'Py'
   >>> word[4:]   # characters from position 4 (included) to the end
   'on'
   >>> word[-2:]  # characters from the second-last (included) to the end
   'on'

Si noti come l'inizio sia sempre incluso, e la fine sempre esclusa.
Questo fa sì che "s[:i] + s[i:]" è sempre uguale a "s":

   >>> word[:2] + word[2:]
   'Python'
   >>> word[:4] + word[4:]
   'Python'

Un modo per ricordare come funzionano le fette è quello di pensare
agli indici come al punto *tra* caratteri, con il bordo sinistro del
primo carattere numerato 0. Poi il bordo destro dell'ultimo carattere
di una stringa di caratteri *n* ha l'indice *n*, per esempio:

    +---+---+---+---+---+---+
    | P | y | t | h | o | n |
    +---+---+---+---+---+---+
    0   1   2   3   4   5   6
   -6  -5  -4  -3  -2  -1

La prima riga di numeri dà la posizione degli indici 0...6 nella
stringa; la seconda riga dà i corrispondenti indici negativi. La
porzione da *i* a *j* è costituita da tutti i caratteri tra i bordi
contrassegnati rispettivamente con *i* e *j*.

Per gli indici non negativi, la lunghezza di una fetta è la differenza
degli indici, se entrambi sono entro i limiti.  Per esempio, la
lunghezza di "word[1:3]" è 2.

Il tentativo di utilizzare un indice troppo grande comporta un errore:

   >>> word[42]  # the word only has 6 characters
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   IndexError: string index out of range

Tuttavia, gli indici delle sottostringhe fuori *range* (che superano
la lunghezza della stringa) sono gestiti a modo quando vengono
utilizzati per l'affettamento:

   >>> word[4:42]
   'on'
   >>> word[42:]
   ''

Le stringhe Python non possono essere modificate --- sono *immutable*.
Pertanto, l'assegnazione di una posizione indicizzata nella stringa
comporta un errore:

   >>> word[0] = 'J'
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: 'str' object does not support item assignment
   >>> word[2:] = 'py'
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: 'str' object does not support item assignment

Se avete bisogno di una stringa diversa, dovreste crearne una nuova:

   >>> 'J' + word[1:]
   'Jython'
   >>> word[:2] + 'py'
   'Pypy'

La funzione integrata "len()" restituisce la lunghezza di una stringa:

   >>> s = 'supercalifragilisticexpialidocious'
   >>> len(s)
   34

Vedi anche:

  Tipo Sequenza di Testo --- str
     Le stringhe sono esempi di *tipi di sequenze*, e supportano le
     operazioni comuni supportate da questi tipi di dato.

  Metodi per le Stringhe
     Un gran numero di metodi per le trasformazioni di base e la
     ricerca sono supportati dalle stringhe.

  f-strings
     Stringhe con *expression* incorporate.

  Format String Syntax
     Informazioni sulla formattazione delle stringhe con
     "str.format()".

  Formattazione delle stringhe in stile printf
     Il vecchio metodo di formattazione, quello che prevede un
     template a sinistra dell'operatore "%" è descritto più
     dettagliatamente qui.


3.1.3. Liste
------------

Python conosce un certo numero di tipi di dati *composti*, usati per
raggruppare altri valori.  La più versatile è la *lista*, che può
essere scritta come una lista di valori separati da virgola (elementi)
tra parentesi quadre.  Gli elenchi possono contenere elementi di tipo
diverso, ma di solito gli elementi hanno tutti lo stesso tipo.

   >>> squares = [1, 4, 9, 16, 25]
   >>> squares
   [1, 4, 9, 16, 25]

Come le stringhe (e tutti gli altri tipi built-in *sequence*), le
liste possono essere indicizzate e tagliate:

   >>> squares[0]  # indexing returns the item
   1
   >>> squares[-1]
   25
   >>> squares[-3:]  # slicing returns a new list
   [9, 16, 25]

Gli elenchi supportano anche operazioni come la concatenazione:

   >>> squares + [36, 49, 64, 81, 100]
   [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

A differenza delle stringhe, che sono *immutable*, le liste sono di
tipo *mutable*, cioè è possibile modificarne il contenuto:

   >>> cubes = [1, 8, 27, 65, 125]  # something's wrong here
   >>> 4 ** 3  # the cube of 4 is 64, not 65!
   64
   >>> cubes[3] = 64  # replace the wrong value
   >>> cubes
   [1, 8, 27, 64, 125]

Potete anche aggiungere nuovi elementi alla fine della lista, usando
il *metodo* "list.append()" (vedremo di più riguardo i metodi più
avanti):

   >>> cubes.append(216)  # add the cube of 6
   >>> cubes.append(7 ** 3)  # and the cube of 7
   >>> cubes
   [1, 8, 27, 64, 125, 216, 343]

L'assegnazione semplice in Python non copia mai i dati. Quando assegni
una lista a una variabile, la variabile si riferisce alla *lista
esistente*. Qualsiasi modifica apportata alla lista tramite una
variabile sarà visibile attraverso tutte le altre variabili che si
riferiscono ad essa.:

   >>> rgb = ["Red", "Green", "Blue"]
   >>> rgba = rgb
   >>> id(rgb) == id(rgba)  # they reference the same object
   True
   >>> rgba.append("Alph")
   >>> rgb
   ["Red", "Green", "Blue", "Alph"]

Tutte le operazioni di taglio restituiscono una nuova lista contenente
gli elementi richiesti.  Ciò significa che la seguente sezione
restituisce una nuova shallow copy della list:

   >>> correct_rgba = rgba[:]
   >>> correct_rgba[-1] = "Alpha"
   >>> correct_rgba
   ["Red", "Green", "Blue", "Alpha"]
   >>> rgba
   ["Red", "Green", "Blue", "Alph"]

L'assegnazione a uno slice è anche possibile, per cambiare anche la
dimensione della lista o cancellarne gli elementi completamente:

   >>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
   >>> letters
   ['a', 'b', 'c', 'd', 'e', 'f', 'g']
   >>> # replace some values
   >>> letters[2:5] = ['C', 'D', 'E']
   >>> letters
   ['a', 'b', 'C', 'D', 'E', 'f', 'g']
   >>> # now remove them
   >>> letters[2:5] = []
   >>> letters
   ['a', 'b', 'f', 'g']
   >>> # clear the list by replacing all the elements with an empty list
   >>> letters[:] = []
   >>> letters
   []

La funzione "len()" si applica anche alle liste:

   >>> letters = ['a', 'b', 'c', 'd']
   >>> len(letters)
   4

E' possibile nidificare liste (creare liste contenenti altre liste),
ad esempio:

   >>> a = ['a', 'b', 'c']
   >>> n = [1, 2, 3]
   >>> x = [a, n]
   >>> x
   [['a', 'b', 'c'], [1, 2, 3]]
   >>> x[0]
   ['a', 'b', 'c']
   >>> x[0][1]
   'b'


3.2. Primi passi di programmazione
==================================

Naturalmente, possiamo usare Python per compiti più complicati che
sommare insieme due più due.  Per esempio, possiamo scrivere una prima
sottosequenza della  Successione di Fibonacci come segue:

   >>> # Fibonacci series:
   >>> # the sum of two elements defines the next
   >>> a, b = 0, 1
   >>> while a < 10:
   ...     print(a)
   ...     a, b = b, a+b
   ...
   0
   1
   1
   2
   3
   5
   8

Questo esempio introduce diverse nuove funzionalità.

* La prima riga contiene una *assegnazione multipla*: le variabili "a"
  e "b" ottengono simultaneamente i nuovi valori 0 e 1. Sull'ultima
  riga viene usata di nuovo, dimostrando che le espressioni sul lato
  destro sono tutte valutate prima di una qualsiasi delle
  assegnazioni.  Le espressioni del lato destro sono valutate da
  sinistra a destra.

* Il ciclo "while" viene eseguito finché la condizione (qui: "a < 10")
  rimane vera.  In Python, come in C, qualsiasi valore intero diverso
  da zero è vero; zero è falso.  La condizione può anche essere una
  stringa o un valore di lista, infatti qualsiasi sequenza; qualsiasi
  cosa con una lunghezza diversa da zero è vera, le sequenze vuote
  sono false.  Il test utilizzato nell'esempio è un semplice
  confronto.  Gli operatori di confronto standard sono scritti come in
  C: "<" (minore di), ">" (maggiore di), "==" (uguale a), "<=" (minore
  o uguale a), ">=" (maggiore o uguale a) e "!=" (diverso da).

* Il *corpo* del ciclo è *indentato*: l'indentazione è il modo di
  Python di raggruppare le istruzioni.  Al prompt interattivo, è
  necessario digitare un tab o spazio/i per ogni riga rientrata.  In
  pratica si prepara un input più complicato per Python con un editor
  di testo; tutti gli editor di testo seri hanno una funzione di auto-
  indentazione.  Quando un'istruzione composta è inserita nella shell
  interattiva, deve essere seguita da una riga vuota per indicare il
  completamento (poiché l'analizzatore non può indovinare quando si è
  digitata l'ultima riga).  Si noti che ogni riga all'interno di un
  blocco di base deve essere rientrata della stessa quantità.

* The "print()" function writes the value of the argument(s) it is
  given. It differs from just writing the expression you want to write
  (as we did earlier in the calculator examples) in the way it handles
  multiple arguments, floating-point quantities, and strings.  Strings
  are printed without quotes, and a space is inserted between items,
  so you can format things nicely, like this:

     >>> i = 256*256
     >>> print('The value of i is', i)
     The value of i is 65536

  L'argomento *end* può essere usato per evitare la nuova linea dopo
  l'output, o terminare l'output con una stringa diversa:

     >>> a, b = 0, 1
     >>> while a < 1000:
     ...     print(a, end=',')
     ...     a, b = b, a+b
     ...
     0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,

-[ Note ]-

[1] Poiché "**" ha una precedenza superiore a "-", "-3**2" sarà
    interpretato come "-(3**2)" e quindi risulterà in "-9".  Per
    evitare questo e ottenere "9", è possibile utilizzare "(-3)**2".

[2] A differenza di altri linguaggi, i caratteri speciali come "\n"
    hanno lo stesso significato sia con apici singoli ("’…’") che
    doppi ("”…”"). L'unica differenza tra i due è che all'interno
    delle stringhe ad apici singoli non c’è bisogno di aggiungere il
    carattere di escaping prima del """ (ma bisogna inserirlo prima di
    un "\'") e viceversa.
