<jupyter_start><jupyter_text>Comandamenti Il Comitato Supremo per la Dottrina del Coding ha emanato importanti comandamenti che seguirai scrupolosamente.Se accetti le loro sagge parole, diventerai un vero Jedi Python. **ATTENZIONE**:  se non segui i Comandamenti, finirai nel _Debugging Hell_ !  I COMANDAMENTO**Scriverai codice Python**Chi non scrive codice Python, non impara Python  II COMANDAMENTO**Quando inserisci una variabile in un ciclo** `for`**, questa variabile deve essere nuova** Se hai definito la variabile prima, non la reintrodurrai in un `for`, perchè ciò portebbe confusione nelle menti di chi legge.Perciò evita questi peccati:<jupyter_code>i = 7
for i in range(3):  # peccato, perdi la variabile i
    print(i)
    
print(i)   # stampa 2 e non 7  !!
def f(i):
    for i in range(3): # altro peccato, perdi il parametro i
        print(i)
    
    print(i)  # stampa 2, e non il 7 che gli abbiamo passato !
    
f(7)
for i in range(2):      
    
    for i in  range(5):  # inferno da debuggare, perdi l'i del ciclo for esterno
        print(i)
        
    print(i)  # stampa 4 !!<jupyter_output>0
1
2
3
4
4
0
1
2
3
4
4<jupyter_text>III COMANDAMENTO**Noi riassegnerai mai parametri di funzione**Non farai mai nessuna di queste assegnazioni, pena la perdita del parametro passato quando viene chiamata la funzione:<jupyter_code>def peccato(intero):
    intero = 666            # peccato, hai perso il 5 passato dall'esterno !
    print(intero)           # stampa 666
    
x = 5
peccato(x)<jupyter_output>666<jupyter_text>Lo stesso discorso si applica per tutti gli altri tipi:<jupyter_code>def male(stringa):
    stringa = "666"          
def disgrazia(lista):
    lista = [666]
def delirio(dizionario):
    dizionario = {"evil":666}<jupyter_output><empty_output><jupyter_text>Per il solo caso di parametri compositi come liste o dizionari, puoi scrivere come sotto SE E SOLO SE le specifiche della funzione ti richiedono di MODIFICARE gli elementi interni del parametro (come per esempio ordinare una lista o cambiare il campo di un dizionario)<jupyter_code># MODIFICA lista in qualche modo
def consentito(lista):        
    lista[2] = 9         # OK, lo richiede il testo della funzione
    
fuori = [8,5,7]
consentito(fuori)
print(fuori)
# MODIFICA dizionario in qualche modo
def daccordo(dizionario):
    dizionario["mio campo"] = 5       # OK, lo richiede il testo
# MODIFICA istanza in qualche modo
def va_bene(istanza_di_classe):
    istanza_di_classe.mio_campo = 7   # OK, lo richiede il testo<jupyter_output><empty_output><jupyter_text>Se invece il testo di una funzione ti chiede di RITORNARE  un NUOVO oggetto, non cadrai nella tentazione di modificare l'input:<jupyter_code># RITORNA una NUOVA lista ordinata
def dolore(lista):
    lista.sort()           # MALE, stai modificando la lista di input invece di crearne una nuova!
    return lista
# RITORNA una NUOVA lista 
def crisi(lista):
    lista[0] = 5           # MALE, come sopra
    return lista
# RITORNA un NUOVO dizionario 
def tormento(dizionario):
    dizionario['a'] = 6    # MALE, stai modificando il dizionario di input 
                           # invece di crearne uno nuovo!
    return dizionario
# RITORNA una NUOVA istanza di classe
def disperazione(istanza):
    istanza.mio_campo = 6  # MALE, stai modificando l'oggetto di input
                           # invece di crearne uno nuovo!
    return istanza<jupyter_output><empty_output><jupyter_text>IV COMANDAMENTO**Non riassegnerai mai valori a chiamate a funzioni o metodi**```pythonmia_funzione() = 666       SBAGLIATO mia_funzione() = 'evil'    SBAGLIATOmia_funzione() = [666]     SBAGLIATO``````pythonx = 5                      OKy = my_fun()               OKz = []                     OKz[0] = 7                   OKd = dict()                 OKd["a"] = 6                 OK```Chiamate a funzione come `mia_funzione()` ritornano risultati di calcoli e li mettono in una scatola che è creata solo per lo scopo della chiamata e Python non ci consentirà di riusarla come una variabile. Quando vedi `nome()` alla parte sinistra, _non può_ essere seguito da un segno di uguaglianza `=` (ma può essere seguito da due segni di uguaglianza `==` se stai eseguendo una comparazione).  V COMANDAMENTO**Non ridifinerai mai funzioni di sistema**Python ha diverse funzioni di sistema predefinite. Per esempio `list` è un tipo Python: come tale, puoi usarlo per esempio come funzione per convertire un qualche tipo a lista:<jupyter_code>list("ciao")<jupyter_output><empty_output><jupyter_text>Quando consenti alle Forze del Male di prendere il sopravvento, potresti essere tentato di usare tipi e funzioni di sistema (per es. `list`) come una variabile per i tuoi miserabili propositi personali:```pythonlist = ['la', 'mia', 'lista', 'raccapricciante']``` Python ti permette di farlo, ma **noi no**, poichè le conseguenze sono disastrose. Per esempio, se adesso usi `list` per il proposito per cui è stata creata, cioè conversione a lista, non funzionerà più: ```pythonlist("ciao")``````---------------------------------------------------------------------------TypeError                                 Traceback (most recent call last) in ()----> 1 list("ciao")TypeError: 'list' object is not callable``` In particolare, raccomandiamo di **non ridefinire** queste preziose funzioni:* `bool`, `int`,`float`,`tuple`,`str`,`list`,`set`,`dict`* `max`, `min`, `sum`* `next`, `iter`* `id`, `dir`, `vars`,`help`  VI COMANDAMENTO**Userai il comando** `return` **solo se vedi scritto RITORNA nella descrizione di funzione!**Se non c'è un RITORNA nella descrizione di funzione, si intende che la funzione ritorni `None`. In questo caso non devi nemmeno scrivere `return None`, perchè Python lo farà implicitamente per te.  VII COMANDAMENTO**Scriverai anche su carta!**Se fissare il monitor non funziona, aiutati e disegna su carta una rappresentazione dello stato del programma. Tabelle, nodi, frecce, tutto può aiutare nel trovare una soluzione al problema.  VIII COMANDAMENTO**Non riassegnerai mai** `self` **!**    Non scriverai mai empietà come questa:<jupyter_code>class MiaClasse:
    def mio_metodo(self):
        self = {'mio_campo':666}<jupyter_output><empty_output><jupyter_text>Dato che `self` è una specie di dizionario, potresti essere tentato di scrivere come sopra, ma al mondo esterno questo non porterà alcun effetto. Per esempio, supponiamo che qualcuno da fuori faccia una chiamata come questa:<jupyter_code>mc = MiaClasse()
mc.mio_metodo()<jupyter_output><empty_output><jupyter_text>Dopo la chiamata `mc` non punterà a `{'mio_campo':666}`<jupyter_code>mc<jupyter_output><empty_output><jupyter_text>e non avrà `mio_campo`: ```pythonmc.mio_campo---------------------------------------------------------------------------AttributeError                            Traceback (most recent call last) in ()----> 1 mc.mio_campoAttributeError: 'MiaClasse' object has no attribute 'mio_campo'``` Per lo stesso ragionamento, non devi riassegnare `self` a liste o altro:<jupyter_code>class MiaClasse:
    def mio_metodo(self):
        self = ['evil'] 
        self = 666<jupyter_output><empty_output><jupyter_text>IX COMANDAMENTO**Testerai il codice!**Il codice non testato per definizione _non funziona_. Per idee su come testare, guarda [Gestione degli errori e testing](errors-and-testing/errors-and-testing-sol.ipynb)  X COMANDAMENTO**Non aggiungerai o toglierai mai elementi da una sequenza che iteri con un** `for` **!**Abbandonarti in simil tentazioni **produrrebbe comportamenti del tutto imprevedibili** (conosci forse l'espressione _tirare il tappeto da sotto i piedi?_ ) **Non aggiungere**, poichè rischi di camminare su un tapis roulant che mai si spegne:```pythonlista = ['a','b','c','d','e']for el in lista:    lista.append(el)   STAI INTASANDO LA MEMORIA DEL COMPUTER``` **Non togliere**, poichè rischi di corrompere l'ordine naturale delle cose:<jupyter_code>lista = ['a','b','c','d','e']

for el in lista:
    lista.remove(el)   # PESSIMA IDEA<jupyter_output><empty_output><jupyter_text>Guarda bene il codice. Credi che abbiamo rimosso tutto, eh?<jupyter_code>lista<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.107366098786616, 'fraction_numerical': 0.009192302978306165, 'mean_word_length': 3.814159292035398, 'pattern_counts': {'":': 1, '<': 47, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '12', 'dir': 'jupyter-structured-clean-dedup', 'id': '668106', 'license': 'CC-BY-4.0', 'n_tokens_mistral': 2905, 'n_tokens_neox': 2841, 'n_words': 921, 'path': 'commandments.ipynb', 'repo_name': 'DavidLeoni/softpython-', 'size': '8159'}