Fondamenti di Programmazione

Andrea Sterbini

28 settembre 2023

RECAP¶

  • info sul corso, homework ed esami
  • Anaconda da installare
  • cenni sugli interi

Cose da fare da parte vostra al più presto¶

1. Iscrivetevi a Q2A.DI.UNIROMA1.IT per poter fare gli homework (HW)¶

ed attivate il corso "Fondamenti di programmazione AA 23-24" nel vostro profilo¶

2. Installate Anaconda: python + Ipython + Spyder IDE e prendere familiarità¶

A casa potete usare lo IDE (Integrated Development Environment) che volete
All'esame avrete a disposizione Spyder (fate esercizio)

Tipi di dati disponibili in Python
(rappresentazione delle informazioni)

Le informazioni elementari sono codificate in modi diversi:

  • INTERI Es. 42
  • BOOLEANI: True/False
  • FLOAT: Es. 3.1415
  • STRINGHE: Es: "Topolino e Pippo abitano a Topolinia"

Interi e "variabili"¶

In [1]:
a = 1
b = 100
c = a + b
print(c)
101

Abbiamo:

  • definito la variabile denominata a col valore 1
    • ovvero aggiunto il nome a alla tabella dei nomi
    • con un riferimento ad un pezzo di memoria che contiene il valore 1
  • definito la variabile denominata b col valore 100
  • definito la variabile denominata c col valore risultato della espressione a+b
  • stampato il contenuto della variabile c
No description has been provided for this image

Domanda: quale è il massimo numero intero che posso esprimere con python?

Dipende dalla memoria del sistema. Quindi più memoria ho, più posso codificare un numero elevato.

Interi nei computer e in python¶

  • I numeri in un computer sono rappresentati da sequenze di bit (voltaggio alto/basso ==> valore uno/zero)
  • Con N posizioni e 2 simboli (sistema binario) posso codificare $2^N$ enumerazioni diverse, cioè un numero da $[0\ldots 2^N-1]$
  • In un sistema a 64 bit, i registri del processore hanno 64 posizioni di 0 o 1
  • se $N=64$, allora posso arrivare a contare fino a $2^{64}-1 \approx 18~\text{Giga}^2$
In [2]:
max_val = 2**64-1
print(max_val) 
18446744073709551615
In [3]:
max_val/10**18
# divido max_val per 10 alla 18 per scoprire quanti miliardi di miliardi sono
# quindi 2**64 equivale a 18.44 miliardi oppure 18.44 G^2
Out[3]:
18.446744073709553

Proviamo con python a convertire
un numero da intero a binario

Con N digit (posizioni) e un set di cifre di base di 2, ossia solo con $\{0,1\}$ posso rappresentare $2^N$ numeri

Ad esempio con $N=3$ bit

Numero pos 2 pos 1 pos 0 base 2
Peso $$2^2=4$$ $$2^1=2$$ $$2^0=1$$
0 0 0 0 000
1 0 0 1 001
2 0 1 0 010
3 0 1 1 011
4 1 0 0 100
5 1 0 1 101
6 1 1 0 110
7 1 1 1 111

Verifichiamo che la rappresentazione sia corretta¶

Prendiamo $(110)_2$ e vediamo se convertendolo torna $(6)_{10}$

In [4]:
# Verifichiamo con python che la rappresentazione sia corretta
# prendiamo 110 in binario e convertiamo in decimale a "mano"
valore_dec = 1*2**2 + 1*2**1 + 0*2**0
# come a scuola, la potenza (**) ha precedenza 
# sulla moltiplicazione (*) che ha precedenza sulla somma

Che valore contiene la variabile di nome valore_dec?¶

Attenzione all'ordine degli operatori

In [5]:
# ok torna, stavamo convertendo 110 in binario a 6 in decimale
valore_dec
Out[5]:
6
  • Se voglio memorizzare anche numeri negativi, un bit dei 64 disponibili serve per codificare il segno, quindi perdo una posizione (un binary digit nella rappresentazione) nel rappresentare il modulo. Restano $N=64-1=63$.
  • Quindi in teoria potrei rappresentare numeri nell'intervallo:
    $$ [-(2^{63}-1),+(2^{63}-1)] $$

Nel linguaggio C (non python) i tipi sono definiti staticamente, cioè a tempo di compilazione

int valore_intero;
valore_intero = 0;

e gli interi in memoria occupano una word (in questo caso 64 bit)

In [6]:
# In python gli interi sono diversi dal C
min_val = -(2**63-1)
max_val = +(2**63-1)
print(min_val)
print(max_val)
-9223372036854775807
9223372036854775807

Dobbiamo andare ancora piu a fondo...

All'esterno di questo intervallo il sistema dovrebbe andare in overflow (straripamento della rappresentazione).

Numero pos 3 pos 2 pos 1 pos 0 base 2
Peso $$2^3=8$$ $$2^2=4$$ $$2^1=2$$ $$2^0=1$$
0 0 0 0 0 000
1 0 0 0 1 001
2 0 0 1 0 010
3 0 0 1 1 011
4 0 1 0 0 100
5 0 1 0 1 101
6 0 1 1 0 110
7 0 1 1 1 111
8 1 0 0 0 1000

NOTATE come il numero 8 non possa essere rappresentato da sole 3 cifre binarie

Per evitare un overflow dobbiamo inserire
un altro digit ma in una word NON ci sono piu di 64 posizioni
e quindi il numero non dovrebbe essere rappresentabile.
Proviamo a vedere cosa succede
incrementando il massimo intero in Python

In [7]:
numero_max = 2**63 - 1
print(numero_max)
9223372036854775807
In [8]:
numero_max += 1   # provo ad aggiungere 1  
print(numero_max) # da o non non da errore di overflow?
9223372036854775808
In [9]:
# sembra che riesca a calcolarsi sempre tutto correttamente
# lo moltiplico per 3 e vediamo cosa succede
numero_max *= 3     # sembra che funzioni tutto
print(numero_max)   
27670116110564327424

DEDUCO che Python NON usa solo una word della CPU
(come il C) per rappresentare gli interi

Ancora sul massimo valore degli interi

Adesso proviamo a calcolare un valore veramente grande

In [10]:
huge_value = 10**1000 
In [11]:
huge_value
Out[11]:
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
In [12]:
hyper_huge_value = 10**4000
In [13]:
hyper_huge_value
Out[13]:
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
In [14]:
hyper_huge_value > huge_value 
# sanity check, controlliamo se davvero hyper_huge_value 
# sia maggiore di  huge_value! 
Out[14]:
True

Perche' riusciamo a calcolare
anche numeri così grandi?

  • Python va oltre interi rappresentati su 64 bit ma puo' usare teoricamente anche l'intera memoria per rappresentare i dati interi

  • Per fare questo si mantiene una rappresentazione interna degli interi in una sorta di array (una sequenza di word in memoria) che può essere grande quanto serve.

  • Questo è invisibile al programmatore ma è bene saperlo (operazioni su numeri molto molto grandi impiegheranno più tempo nelle operazioni invece che un tempo costante)
  • (Qui andiamo negli internals di python che sono scritti in liguaggio C quindi non approfondiamo ... chi è curioso può cercare su Google)
  • Il limite ultimo alla rappresentazione intera di Python e' quindi in teoria la memoria massima del vostro calcolatore (a meno delle parti usate da OS, processi in esecuzione etc.)
In [15]:
import sys  # importiamo il modulo della librerie built-in 
            # in pyton per accedere alle funzionalita' 
            # legate al sistema
sys.maxsize 
# the largest supported length of containers (via help(sys))
Out[15]:
9223372036854775807
  • IMPORTANTE: sys.maxsize
    NON e' il massimo intero rappresentabile

MASSIMA LUNGHEZZA DISPONIBILE di un CONTAINER (lista, "vettore", tupla, insieme, dizionario, ...)

In [16]:
2 ** 63 - 1 == sys.maxsize
# sembra proprio che ogni CONTAINER abbia una word 
# (a 64 bit) che indica quanti elementi vi sono contenuti
Out[16]:
True

Operatore di Confronto ==¶

Confronta due espressioni per vedere se i valori sono uguali¶

  • Per controllare se i due interi erano uguali abbiamo usato operatore ==
  • == controlla se due espressioni hanno lo stesso valore (ci torniamo nelle prossime lezioni)
  • Per ora basta NON confondere = (operatore assegnazione) con == operatore di confronto
In [17]:
2 ** 63 - 1 == sys.maxsize     
# == controlliamo se il valore nella espressione a sx
# e' uguale al valore della espressione a dx
# il risultato e' in questo caso un'espressione booleana
# che restituisce un nuovo tipo (che ancora non abbiamo visto)
# di tipo bool (che ha solo uno dei valori True oppure False)
Out[17]:
True

Operatori di confronto

No description has been provided for this image
In [18]:
100 > 100   # con strettamente maggiore rende Falso (False)
Out[18]:
False
In [19]:
100 >= 100  # con il maggiore o uguale rende Vero (True)
Out[19]:
True

Tipo Bool¶

In [20]:
is_larger = hyper_huge_value > huge_value 
# sanity check, 
# controlliamo se davvero hyper_huge_value sia maggiore di 
# huge_value
print(is_larger)
True
In [21]:
type(is_larger)
Out[21]:
bool
In [22]:
1 == True, 0 == False
Out[22]:
(True, True)
In [23]:
# quindi True corrisponde a 1 e False a 0
# controlliamo con altri valori
3 == True, -99 == False
Out[23]:
(False, False)
In [24]:
# vediamo se la parola 'True' equivale a True
'True' == True
# Perchè non sono uguali?
# a sinistra c'è una stringa che contiene i 4 caratteri 'T' 'r' 'u' 'e'
# a destra c'è il valore booleano True
Out[24]:
False
In [25]:
# vediamo quali variabili abbiamo definito
%whos
Variable           Type      Data/Info
--------------------------------------
a                  int       1
b                  int       100
c                  int       101
huge_value         int       1000000000000000000000000<...>0000000000000000000000000
hyper_huge_value   int       1000000000000000000000000<...>0000000000000000000000000
is_larger          bool      True
max_val            int       9223372036854775807
min_val            int       -9223372036854775807
numero_max         int       27670116110564327424
sys                module    <module 'sys' (built-in)>
valore_dec         int       6
In [26]:
c =  101
# Le espressioni sopra per ora non hanno molto senso
# ma una espressione come quella sotto 
# è molto utile.
is_higher_than_100 = c > 100

# E' utile perche' il risultato 
# (True/False)
# della espressione booleana dipende dal
# contenuto della variabile c

# I valori booleani servono al calcolatore
# per prendere decisioni e comportarsi in maniera diversa
# Lo vediamo in seguito
In [27]:
print(c) 
print(is_higher_than_100)
101
True

Tipo floating point (numeri con la virgola) e confronti¶

In [28]:
# cosa succede se confronto un intero con un float
1 == 1.00000000        # NOTA: si usa il '.' punto come separatore
Out[28]:
True
In [29]:
1 == 1.000_000_000_000_001, 1 == 1.000_000_000_000_000_1
# dopo circa 15 cifre decimali la differenza non è più percepibile (vedi dopo)
Out[29]:
(False, True)
In [30]:
# che succede se sommiamo interi e float?
a_intero = 1
b_float  = 1.0
somma = a_intero + b_float
# stampo la somma e il tipo della var. somma
print(somma, type(somma))
2.0 <class 'float'>

Notazione scientifica¶

In [31]:
# possiamo usare la notazione scientifica in base 10
1e-10 > 0
Out[31]:
True

\begin{align*} 10^{-10} > 0 \end{align*} \begin{align*} 0.0000000001 > 0 \end{align*}

\begin{align*} 0.00000000000000000001 > 0 \end{align*}

In [32]:
(1e-20) > 0
Out[32]:
True
In [33]:
# trasformiamolo in una stringa con 100 cifre decimali dopo la virgola
str_f = format(1e-20,'.100f')       # format converte da valori a testo
# stampiamolo e vediamo di che tipo è
print(str_f); print(type(str_f))    
0.0000000000000000000099999999999999994515327145420957165172950370278739244710771577606678306437970605
<class 'str'>
In [34]:
(1 + 1e-20) > 1    # 1 + 1e-20 è maggiore di 1? (sembra di no, perchè?)
Out[34]:
False
In [35]:
format(1+1e-20,'.1000f')         
# vediamo quanto fa ... è come 1!!!
Out[35]:
'1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'

Codifica IEEE-754 per rappresentare i floating point¶

TLDR: i float sono rappresentati su un numero di bit fisso

I float sono approssimati usando una parte dei 64 bit di una word (la mantissa) per rappresentare le cifre (binarie) più significative, moltiplicate per una potenza di 2 (esponente):

segno mantissa esponente
1 bit 53 bit 10 bit

$$\text{valore} = -1^\text{segno} * 1.\text{mantissa} * 2^\text{esponente}$$

  • Mantissa: 53 bit iniziando dal 2° bit
    più significativo del numero (in binario)
  • Esponente: potenza di 2 che porta il bit più significativo a sx

Esempio il numero

numero binario float normalizzato diventa segno mantissa esponente
-100.11 -1.0011 * $2^2$ 1 0011 10

Da Novembre 2000 tutti i calcolatori rappresentano i float seguendo lo standard IEEE-754.

NOTA: in realtà all'esponente viene aggiunto un offset per rappresentare valori negativi e positivi

Per sommare due numeri dobbiamo "mettere in colonna le virgole"¶

Ovvero rendere gli esponenti uguali

Quindi non è possibile sommare numeri con un rapporto maggiore di $2^{53}$¶

In [84]:
# Provo sommare 1 a 2^-53 per confrontarlo con 1
1 + (2**-53)
# il numero sommato è troppo piccolo per cambiare 1
# le sue cifre verranno ignorate nella somma
Out[84]:
1.0
In [37]:
# quante cifre decimali corrispondono a 2^53?
2**53 / 10**16
# Circa 16!!! ecco perchè prima il contronto
# si comportava così!
Out[37]:
0.9007199254740992

Interi¶

  • Memoria variabile, garantiscono precisione teoricamente ~infinita~ (ovviamente no, finita in base alla memoria del calcolatore)
  • Codificano solo operazioni con interi

Float¶

  • Modellano numeri reali (razionali e irrazionali) ma hanno una precisione finita
  • Su macchine a 64 bit solo 53 bit sono dedicati alla precisione del numero (pari a circa 16 cifre decimali)

Chi vuole approfondire https://docs.python.org/3/tutorial/floatingpoint.html

Altre operazioni su interi importanti

Abbiamo visto:

  • somma a+b
  • sottrazione a-b
  • prodotto a*b
  • divisione a/b
  • potenza a**b

In Python ci sono due tipi di divisione:

  1. Divisione floating point /
    • Produce sempre un float int/int --> float
  1. Divisione intera si fa con a // b
    • Rende un int se i due valori sono int
      int//int --> int
    • Rende un float altrimenti
      int // float --> float
      float // int --> float
      float // float --> float

Divisione intera fra a e b $$ a = b \cdot \mathbf{q} + \mathbf{r}$$

  1. Il resto della divisione intera si ottiene con a % b
In [38]:
# Per ora abbiamo visto la divisione con decimali
a = 5
b = 3
q = a/b 
q
Out[38]:
1.6666666666666667
In [39]:
type(q)       # con type ottengo il tipo del dato
Out[39]:
float

Quoziente Intero e Resto¶

In [40]:
# altro tipo di divisione. Quella intera
a = 5
b = 3
q = a // b # stiamo dividendo 5 con 3 ossia 5//3
q
Out[40]:
1
In [41]:
r = a % b # resto della divisione si calcola con %
# resto di 5/3
r
Out[41]:
2
In [42]:
# sanity check
a_check = b*q + r  
a_check == a  # Controllo se vale 5 =? 3*1 + 2
Out[42]:
True

Ri-assegnazione e ancora operatore di assegnazione ('=')¶

Le variabili possono essere modificate a piacere
(da qui il nome "variabili")

In [43]:
x = 5
# x ora vale 5
print(x)
5
In [44]:
x = 7
# quanto vale ora x? Che ne e' di 5?
print(x)
7
No description has been provided for this image

Istruzione di assegnazione potenziata

  • Spesso capita di avere un valore di x
  • Di volergli applicare una operazione
    (per es. operazione aritmetica)
  • Ed inserire il risultato di nuovo in x
In [45]:
x = 0 
x = x + 1

# Senza dover ripetere il nome della variabile scrivo
x += 1     # incrementa x di 1
x
Out[45]:
2

Come leggere gli assegnamenti¶

  1. [DESTRA del =] Prendi l'espressione x+1, calcolane il valore
  2. [SINISTRA del = ] Usa operatore di assegnazione per scrivere il valore calcolato di nuovo dentro x
  3. x <== x + 1 con pseudo codice
In [46]:
# e' possibile scrivere questa istruzione anche 
# in maniera piu compatta senza ripetere la variabile come
y = 0
print(y)
y += 1 # equivale a y = y + 1 
# come i++ in altri linguaggi 
print(y)
0
1
No description has been provided for this image
In [47]:
# questo vale anche per altre operazioni aritmetiche
i = 1
i *= 2     # equivale ad    i = i * 2
In [48]:
i
Out[48]:
2
In [49]:
i *= 2
In [50]:
i
Out[50]:
4
In [51]:
i = i * 2

Quanto vale ora i ?

In [52]:
i
Out[52]:
8
In [53]:
i *= 2
In [54]:
i
Out[54]:
16

STRINGHE (testo)¶

Dall'inglese

to string (legare insieme)

  • codificano una sequenza arbitrariamente lunga di caratteri
  • Possono rappresentare del testo
  • Anche il testo nel calcolatore è rappresentato come numeri (binari) attraverso una codifica di ciascun carattere
In [55]:
a = 'spam eggs'  # single quotes

b = "doesn't"  # ...or use double quotes instead
In [56]:
a, b
Out[56]:
('spam eggs', "doesn't")
In [57]:
type(a),type(b)
Out[57]:
(str, str)

help() <-- MOLTO IMPORTANTE SOPRATTUTTO ALL'ESAME

Oppure potete usare l'help contestuale di Spyder

Oppure il comando pydoc da terminale

In [58]:
help(str) # se invocato sul tipo str vi mostra la documentazione delle stringhe :D
Help on class str in module builtins:

class str(object)
 |  str(object='') -> str
 |  str(bytes_or_buffer[, encoding[, errors]]) -> str
 |  
 |  Create a new string object from the given object. If encoding or
 |  errors is specified, then the object must expose a data buffer
 |  that will be decoded using the given encoding and error handler.
 |  Otherwise, returns the result of object.__str__() (if defined)
 |  or repr(object).
 |  encoding defaults to sys.getdefaultencoding().
 |  errors defaults to 'strict'.
 |  
 |  Methods defined here:
 |  
 |  __add__(self, value, /)
 |      Return self+value.
 |  
 |  __contains__(self, key, /)
 |      Return key in self.
 |  
 |  __eq__(self, value, /)
 |      Return self==value.
 |  
 |  __format__(self, format_spec, /)
 |      Return a formatted version of the string as described by format_spec.
 |  
 |  __ge__(self, value, /)
 |      Return self>=value.
 |  
 |  __getattribute__(self, name, /)
 |      Return getattr(self, name).
 |  
 |  __getitem__(self, key, /)
 |      Return self[key].
 |  
 |  __getnewargs__(...)
 |  
 |  __gt__(self, value, /)
 |      Return self>value.
 |  
 |  __hash__(self, /)
 |      Return hash(self).
 |  
 |  __iter__(self, /)
 |      Implement iter(self).
 |  
 |  __le__(self, value, /)
 |      Return self<=value.
 |  
 |  __len__(self, /)
 |      Return len(self).
 |  
 |  __lt__(self, value, /)
 |      Return self<value.
 |  
 |  __mod__(self, value, /)
 |      Return self%value.
 |  
 |  __mul__(self, value, /)
 |      Return self*value.
 |  
 |  __ne__(self, value, /)
 |      Return self!=value.
 |  
 |  __repr__(self, /)
 |      Return repr(self).
 |  
 |  __rmod__(self, value, /)
 |      Return value%self.
 |  
 |  __rmul__(self, value, /)
 |      Return value*self.
 |  
 |  __sizeof__(self, /)
 |      Return the size of the string in memory, in bytes.
 |  
 |  __str__(self, /)
 |      Return str(self).
 |  
 |  capitalize(self, /)
 |      Return a capitalized version of the string.
 |      
 |      More specifically, make the first character have upper case and the rest lower
 |      case.
 |  
 |  casefold(self, /)
 |      Return a version of the string suitable for caseless comparisons.
 |  
 |  center(self, width, fillchar=' ', /)
 |      Return a centered string of length width.
 |      
 |      Padding is done using the specified fill character (default is a space).
 |  
 |  count(...)
 |      S.count(sub[, start[, end]]) -> int
 |      
 |      Return the number of non-overlapping occurrences of substring sub in
 |      string S[start:end].  Optional arguments start and end are
 |      interpreted as in slice notation.
 |  
 |  encode(self, /, encoding='utf-8', errors='strict')
 |      Encode the string using the codec registered for encoding.
 |      
 |      encoding
 |        The encoding in which to encode the string.
 |      errors
 |        The error handling scheme to use for encoding errors.
 |        The default is 'strict' meaning that encoding errors raise a
 |        UnicodeEncodeError.  Other possible values are 'ignore', 'replace' and
 |        'xmlcharrefreplace' as well as any other name registered with
 |        codecs.register_error that can handle UnicodeEncodeErrors.
 |  
 |  endswith(...)
 |      S.endswith(suffix[, start[, end]]) -> bool
 |      
 |      Return True if S ends with the specified suffix, False otherwise.
 |      With optional start, test S beginning at that position.
 |      With optional end, stop comparing S at that position.
 |      suffix can also be a tuple of strings to try.
 |  
 |  expandtabs(self, /, tabsize=8)
 |      Return a copy where all tab characters are expanded using spaces.
 |      
 |      If tabsize is not given, a tab size of 8 characters is assumed.
 |  
 |  find(...)
 |      S.find(sub[, start[, end]]) -> int
 |      
 |      Return the lowest index in S where substring sub is found,
 |      such that sub is contained within S[start:end].  Optional
 |      arguments start and end are interpreted as in slice notation.
 |      
 |      Return -1 on failure.
 |  
 |  format(...)
 |      S.format(*args, **kwargs) -> str
 |      
 |      Return a formatted version of S, using substitutions from args and kwargs.
 |      The substitutions are identified by braces ('{' and '}').
 |  
 |  format_map(...)
 |      S.format_map(mapping) -> str
 |      
 |      Return a formatted version of S, using substitutions from mapping.
 |      The substitutions are identified by braces ('{' and '}').
 |  
 |  index(...)
 |      S.index(sub[, start[, end]]) -> int
 |      
 |      Return the lowest index in S where substring sub is found,
 |      such that sub is contained within S[start:end].  Optional
 |      arguments start and end are interpreted as in slice notation.
 |      
 |      Raises ValueError when the substring is not found.
 |  
 |  isalnum(self, /)
 |      Return True if the string is an alpha-numeric string, False otherwise.
 |      
 |      A string is alpha-numeric if all characters in the string are alpha-numeric and
 |      there is at least one character in the string.
 |  
 |  isalpha(self, /)
 |      Return True if the string is an alphabetic string, False otherwise.
 |      
 |      A string is alphabetic if all characters in the string are alphabetic and there
 |      is at least one character in the string.
 |  
 |  isascii(self, /)
 |      Return True if all characters in the string are ASCII, False otherwise.
 |      
 |      ASCII characters have code points in the range U+0000-U+007F.
 |      Empty string is ASCII too.
 |  
 |  isdecimal(self, /)
 |      Return True if the string is a decimal string, False otherwise.
 |      
 |      A string is a decimal string if all characters in the string are decimal and
 |      there is at least one character in the string.
 |  
 |  isdigit(self, /)
 |      Return True if the string is a digit string, False otherwise.
 |      
 |      A string is a digit string if all characters in the string are digits and there
 |      is at least one character in the string.
 |  
 |  isidentifier(self, /)
 |      Return True if the string is a valid Python identifier, False otherwise.
 |      
 |      Call keyword.iskeyword(s) to test whether string s is a reserved identifier,
 |      such as "def" or "class".
 |  
 |  islower(self, /)
 |      Return True if the string is a lowercase string, False otherwise.
 |      
 |      A string is lowercase if all cased characters in the string are lowercase and
 |      there is at least one cased character in the string.
 |  
 |  isnumeric(self, /)
 |      Return True if the string is a numeric string, False otherwise.
 |      
 |      A string is numeric if all characters in the string are numeric and there is at
 |      least one character in the string.
 |  
 |  isprintable(self, /)
 |      Return True if the string is printable, False otherwise.
 |      
 |      A string is printable if all of its characters are considered printable in
 |      repr() or if it is empty.
 |  
 |  isspace(self, /)
 |      Return True if the string is a whitespace string, False otherwise.
 |      
 |      A string is whitespace if all characters in the string are whitespace and there
 |      is at least one character in the string.
 |  
 |  istitle(self, /)
 |      Return True if the string is a title-cased string, False otherwise.
 |      
 |      In a title-cased string, upper- and title-case characters may only
 |      follow uncased characters and lowercase characters only cased ones.
 |  
 |  isupper(self, /)
 |      Return True if the string is an uppercase string, False otherwise.
 |      
 |      A string is uppercase if all cased characters in the string are uppercase and
 |      there is at least one cased character in the string.
 |  
 |  join(self, iterable, /)
 |      Concatenate any number of strings.
 |      
 |      The string whose method is called is inserted in between each given string.
 |      The result is returned as a new string.
 |      
 |      Example: '.'.join(['ab', 'pq', 'rs']) -> 'ab.pq.rs'
 |  
 |  ljust(self, width, fillchar=' ', /)
 |      Return a left-justified string of length width.
 |      
 |      Padding is done using the specified fill character (default is a space).
 |  
 |  lower(self, /)
 |      Return a copy of the string converted to lowercase.
 |  
 |  lstrip(self, chars=None, /)
 |      Return a copy of the string with leading whitespace removed.
 |      
 |      If chars is given and not None, remove characters in chars instead.
 |  
 |  partition(self, sep, /)
 |      Partition the string into three parts using the given separator.
 |      
 |      This will search for the separator in the string.  If the separator is found,
 |      returns a 3-tuple containing the part before the separator, the separator
 |      itself, and the part after it.
 |      
 |      If the separator is not found, returns a 3-tuple containing the original string
 |      and two empty strings.
 |  
 |  removeprefix(self, prefix, /)
 |      Return a str with the given prefix string removed if present.
 |      
 |      If the string starts with the prefix string, return string[len(prefix):].
 |      Otherwise, return a copy of the original string.
 |  
 |  removesuffix(self, suffix, /)
 |      Return a str with the given suffix string removed if present.
 |      
 |      If the string ends with the suffix string and that suffix is not empty,
 |      return string[:-len(suffix)]. Otherwise, return a copy of the original
 |      string.
 |  
 |  replace(self, old, new, count=-1, /)
 |      Return a copy with all occurrences of substring old replaced by new.
 |      
 |        count
 |          Maximum number of occurrences to replace.
 |          -1 (the default value) means replace all occurrences.
 |      
 |      If the optional argument count is given, only the first count occurrences are
 |      replaced.
 |  
 |  rfind(...)
 |      S.rfind(sub[, start[, end]]) -> int
 |      
 |      Return the highest index in S where substring sub is found,
 |      such that sub is contained within S[start:end].  Optional
 |      arguments start and end are interpreted as in slice notation.
 |      
 |      Return -1 on failure.
 |  
 |  rindex(...)
 |      S.rindex(sub[, start[, end]]) -> int
 |      
 |      Return the highest index in S where substring sub is found,
 |      such that sub is contained within S[start:end].  Optional
 |      arguments start and end are interpreted as in slice notation.
 |      
 |      Raises ValueError when the substring is not found.
 |  
 |  rjust(self, width, fillchar=' ', /)
 |      Return a right-justified string of length width.
 |      
 |      Padding is done using the specified fill character (default is a space).
 |  
 |  rpartition(self, sep, /)
 |      Partition the string into three parts using the given separator.
 |      
 |      This will search for the separator in the string, starting at the end. If
 |      the separator is found, returns a 3-tuple containing the part before the
 |      separator, the separator itself, and the part after it.
 |      
 |      If the separator is not found, returns a 3-tuple containing two empty strings
 |      and the original string.
 |  
 |  rsplit(self, /, sep=None, maxsplit=-1)
 |      Return a list of the substrings in the string, using sep as the separator string.
 |      
 |        sep
 |          The separator used to split the string.
 |      
 |          When set to None (the default value), will split on any whitespace
 |          character (including \\n \\r \\t \\f and spaces) and will discard
 |          empty strings from the result.
 |        maxsplit
 |          Maximum number of splits (starting from the left).
 |          -1 (the default value) means no limit.
 |      
 |      Splitting starts at the end of the string and works to the front.
 |  
 |  rstrip(self, chars=None, /)
 |      Return a copy of the string with trailing whitespace removed.
 |      
 |      If chars is given and not None, remove characters in chars instead.
 |  
 |  split(self, /, sep=None, maxsplit=-1)
 |      Return a list of the substrings in the string, using sep as the separator string.
 |      
 |        sep
 |          The separator used to split the string.
 |      
 |          When set to None (the default value), will split on any whitespace
 |          character (including \\n \\r \\t \\f and spaces) and will discard
 |          empty strings from the result.
 |        maxsplit
 |          Maximum number of splits (starting from the left).
 |          -1 (the default value) means no limit.
 |      
 |      Note, str.split() is mainly useful for data that has been intentionally
 |      delimited.  With natural text that includes punctuation, consider using
 |      the regular expression module.
 |  
 |  splitlines(self, /, keepends=False)
 |      Return a list of the lines in the string, breaking at line boundaries.
 |      
 |      Line breaks are not included in the resulting list unless keepends is given and
 |      true.
 |  
 |  startswith(...)
 |      S.startswith(prefix[, start[, end]]) -> bool
 |      
 |      Return True if S starts with the specified prefix, False otherwise.
 |      With optional start, test S beginning at that position.
 |      With optional end, stop comparing S at that position.
 |      prefix can also be a tuple of strings to try.
 |  
 |  strip(self, chars=None, /)
 |      Return a copy of the string with leading and trailing whitespace removed.
 |      
 |      If chars is given and not None, remove characters in chars instead.
 |  
 |  swapcase(self, /)
 |      Convert uppercase characters to lowercase and lowercase characters to uppercase.
 |  
 |  title(self, /)
 |      Return a version of the string where each word is titlecased.
 |      
 |      More specifically, words start with uppercased characters and all remaining
 |      cased characters have lower case.
 |  
 |  translate(self, table, /)
 |      Replace each character in the string using the given translation table.
 |      
 |        table
 |          Translation table, which must be a mapping of Unicode ordinals to
 |          Unicode ordinals, strings, or None.
 |      
 |      The table must implement lookup/indexing via __getitem__, for instance a
 |      dictionary or list.  If this operation raises LookupError, the character is
 |      left untouched.  Characters mapped to None are deleted.
 |  
 |  upper(self, /)
 |      Return a copy of the string converted to uppercase.
 |  
 |  zfill(self, width, /)
 |      Pad a numeric string with zeros on the left, to fill a field of the given width.
 |      
 |      The string is never truncated.
 |  
 |  ----------------------------------------------------------------------
 |  Static methods defined here:
 |  
 |  __new__(*args, **kwargs) from builtins.type
 |      Create and return a new object.  See help(type) for accurate signature.
 |  
 |  maketrans(...)
 |      Return a translation table usable for str.translate().
 |      
 |      If there is only one argument, it must be a dictionary mapping Unicode
 |      ordinals (integers) or characters to Unicode ordinals, strings or None.
 |      Character keys will be then converted to ordinals.
 |      If there are two arguments, they must be strings of equal length, and
 |      in the resulting dictionary, each character in x will be mapped to the
 |      character at the same position in y. If there is a third argument, it
 |      must be a string, whose characters will be mapped to None in the result.

In [85]:
# posso lanciare comandi del sistema precedendoli con !
!pydoc str.find
Help on method_descriptor in str:

str.find = find(...)
    S.find(sub[, start[, end]]) -> int
    
    Return the lowest index in S where substring sub is found,
    such that sub is contained within S[start:end].  Optional
    arguments start and end are interpreted as in slice notation.
    
    Return -1 on failure.

In [60]:
a,b
Out[60]:
('spam eggs', "doesn't")
In [61]:
'"Yes," they said.' 
# e' una stringa valida perchè inizia e termina con ' e 
# SOLO dentro la stringa compare come carattere "
# quindi il " dentro la stringa e' interpretato come carattere 
# non come inizio di un'altra stringa
Out[61]:
'"Yes," they said.'

Come fare se vogliamo inserire ' dentro una stringa che inizia e termina per '

In [62]:
stringa = 'I know Italian pretty well but I don't know English that well'
  Cell In[62], line 1
    stringa = 'I know Italian pretty well but I don't know English that well'
                                                                            ^
SyntaxError: unterminated string literal (detected at line 1)
In [63]:
# dobbiamo dire a python che la stringa non si chiude 
# a dont' ma a well
# possiamo fare escaping del carattere ' 
# dove vogliamo che sia considerato un carattere e NON 
# un delimitatore di stringa
stringa = 'I know Italian pretty well but I don\'t know English that well'

backslash ---> \ indica che il carattere seguente va trattato in modo diverso

Sequenze di escape utili¶

  • accapo: \n
  • tabulazione: \t
  • backslash: \\
  • doppio apice:\"
  • singolo apice:\'
In [64]:
print(stringa)
I know Italian pretty well but I don't know English that well
In [65]:
stringa = "I know Italian pretty well but I don\"t know English that well"
In [66]:
print(stringa)
I know Italian pretty well but I don"t know English that well
In [67]:
corso = 'Fondamenti di Programmazione\n'
# print stampa \n 
# e anche la stringa codifica \n, 
# quindi in totale abbiamo 2 newline per print
print(corso)
print(corso) 
Fondamenti di Programmazione

Fondamenti di Programmazione

In [68]:
win_path = 'C:\\Documenti\\nautilus'
# sono costretto a mettere doppio \
print(win_path)
# NOTA: negli esercizi d'esame usate solo "/" come separatore dei path
C:\Documenti\nautilus
In [89]:
# La r davanti rende la stringa raw (lasciata grezza com'è scritta)
# in cui non devono essere decodificate le sequenze di escape
win_path = r'C:\Documenti\nautilus'
print(win_path)
# NOTA: inserire un ' diventa problematico
win_path = r'C:\Docume\'nti\nautilus'
print(win_path)
C:\Documenti\nautilus
C:\Docume\'nti\nautilus

Operazioni su stringhe¶

  • NOTA: le stringhe SONO IMMUTABILI!!!

Alcuni operatori "aritmetici" funzionano anche sulle stringhe con significato DIVERSO

In [70]:
# Operatore '+' su stringhe le concatena
# creando una NUOVA stringa
prefix = 'Fondamenti'
postfix = 'Programmazione'
corso = prefix + ' di ' + postfix
print(corso)
Fondamenti di Programmazione
In [71]:
# Operatore * su stringhe
# ripete la concatenazione N volte
# (creando una NUOVA stringa)
prefix = 'Fondamenti '
corso = 5*prefix
print(corso)
'-'*57
# la concatenazione multipla funziona in entrambi i casi
# int * stringa
# stringa * int
Fondamenti Fondamenti Fondamenti Fondamenti Fondamenti 
Out[71]:
'---------------------------------------------------------'

E' possibile convertire da Intero a Stringa

In [72]:
a = 237
s = str(a)
In [73]:
s, a
Out[73]:
('237', 237)
In [74]:
s == a
# che chiaramente sono cose diverse!
Out[74]:
False

Da Stringa a Intero

In [75]:
l = int('10')
print(l)
type(l)
10
Out[75]:
int
In [76]:
## Convertiamo da stringa a intero
## questo e' interessante
s = int('a')
print(s)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[76], line 3
      1 ## Convertiamo da stringa a intero
      2 ## questo e' interessante
----> 3 s = int('a')
      4 print(s)

ValueError: invalid literal for int() with base 10: 'a'
In [77]:
# ma se cambio base e uso base 16 la lettera 'a' 
# è valida come cifra (vale 10)
h = int('a', base=16)
h
Out[77]:
10
In [78]:
## Convertiamo da stringa a intero
## questo e' interessante
s = int('1.45') 
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[78], line 3
      1 ## Convertiamo da stringa a intero
      2 ## questo e' interessante
----> 3 s = int('1.45') 

ValueError: invalid literal for int() with base 10: '1.45'
In [79]:
s = float('1.45')
print(s)
1.45
In [80]:
# CHE SUCCEDE SE FACCIO COSI'?

x = str(int('101') + 50)
x *= int(str('2')) 
In [81]:
x
Out[81]:
'151151'
In [82]:
# che è lo stesso di x = x * int(str('2'))
y = x + x
y, type(y)
Out[82]:
('151151151151', str)