Browse Source

Aggiunto paragrafo su funzioni e scripts

andrea 2 months ago
parent
commit
4fa08e432a
5 changed files with 416 additions and 33 deletions
  1. 361 33
      introduzione_al_coding.md
  2. BIN
      pdf/README.pdf
  3. BIN
      pdf/introduzione_al_coding.pdf
  4. 34 0
      scripts/backup.py
  5. 21 0
      scripts/cesar.py

+ 361 - 33
introduzione_al_coding.md

@@ -240,9 +240,8 @@ ciclo `for`. Genera la soluzione dell'esercizio.
 
 **llm**:
 
-Esercizio:
-
-Scrivi uno script Python che stampi la somma dei primi n numeri naturali, dove n è un numero intero fornito dall'utente.
+Scrivi uno script Python che stampi la somma dei primi n numeri
+naturali, dove n è un numero intero fornito dall'utente.
 
 Traccia dell'esercizio:
 
@@ -305,23 +304,54 @@ al risultato della chiamata ricorsiva.
 
 **llm**:
 
-In Python, le strutture dati sono fondamentali per l'organizzazione e la manipolazione dei dati. Le principali strutture dati in Python includono:
-
-- **Liste**: Sono collezioni ordinate e mutabili di elementi. Possono contenere elementi di diversi tipi. Le liste supportano operazioni come l'aggiunta, la rimozione e l'ordine degli elementi. Possono anche essere usate come pile, dove l'ultimo elemento aggiunto è il primo a essere rimosso (Last-In, First-Out) [5.1.1].
-
-- **Tuple**: Simili alle liste, ma sono immutabili. Le tuple possono essere usate per raggruppare dati correlati e possono essere utilizzate come chiavi in un dizionario. Le tuple possono essere create con una sintassi particolare per le tuple vuote e quelle con un solo elemento [5.3].
-
-- **Dizionari**: Sono collezioni non ordinate di elementi immutabili. Ogni elemento in un dizionario è una coppia chiave-valore. I dizionari sono utilizzati per memorizzare dati in modo chiave-valore e supportano operazioni come l'aggiunta, la rimozione e la ricerca di elementi [5.5].
-
-- **Set**: Sono collezioni non ordinate e immutabili di elementi unici. I set supportano operazioni come l'aggiunta, la rimozione e la ricerca di elementi. I set possono essere utilizzati per eliminare i duplicati da una sequenza [5.4].
-
-Python offre anche tecniche di iterazione per lavorare con queste strutture dati, come l'uso di `items()` per iterare su un dizionario, `enumerate()` per iterare su una sequenza con indici, e `zip()` per iterare su due o più sequenze contemporaneamente. Per iterare su una sequenza in ordine inverso, si può usare `reversed()`, e per iterare in modo ordinato, si può usare `sorted()` [5.6].
-
-Le liste possono essere estese con operazioni come l'aggiunta di elementi alla fine con `append()`, l'inserimento di elementi in una posizione specifica con `insert()`, e la rimozione di elementi con `pop()` o `del` [5.1.1][5.2].
-
-Le **List Comprehension** sono un modo conciso per creare liste basate su altre liste o iterabili, con la possibilità di includere condizioni. Sono particolarmente utili per creare nuove liste da esistenti in modo efficiente [5.1.3].
-
-Infine, Python supporta il confronto tra sequenze e altri tipi di dati, permettendo confronti lessicografici tra elementi di sequenze dello stesso tipo. Questo è utile per l'ordinamento e la comparazione di dati [5.8].
+In Python, le strutture dati sono fondamentali per l'organizzazione e
+la manipolazione dei dati. Le principali strutture dati in Python
+includono:
+
+- **Liste**: Sono collezioni ordinate e mutabili di elementi. Possono
+  contenere elementi di diversi tipi. Le liste supportano operazioni
+  come l'aggiunta, la rimozione e l'ordine degli elementi. Possono
+  anche essere usate come pile, dove l'ultimo elemento aggiunto è il
+  primo a essere rimosso (Last-In, First-Out) [5.1.1].
+
+- **Tuple**: Simili alle liste, ma sono immutabili. Le tuple possono
+  essere usate per raggruppare dati correlati e possono essere
+  utilizzate come chiavi in un dizionario. Le tuple possono essere
+  create con una sintassi particolare per le tuple vuote e quelle con
+  un solo elemento [5.3].
+
+- **Dizionari**: Sono collezioni non ordinate di elementi
+  immutabili. Ogni elemento in un dizionario è una coppia
+  chiave-valore. I dizionari sono utilizzati per memorizzare dati in
+  modo chiave-valore e supportano operazioni come l'aggiunta, la
+  rimozione e la ricerca di elementi [5.5].
+
+- **Set**: Sono collezioni non ordinate e immutabili di elementi
+  unici. I set supportano operazioni come l'aggiunta, la rimozione e
+  la ricerca di elementi. I set possono essere utilizzati per
+  eliminare i duplicati da una sequenza [5.4].
+
+Python offre anche tecniche di iterazione per lavorare con queste
+strutture dati, come l'uso di `items()` per iterare su un dizionario,
+`enumerate()` per iterare su una sequenza con indici, e `zip()` per
+iterare su due o più sequenze contemporaneamente. Per iterare su una
+sequenza in ordine inverso, si può usare `reversed()`, e per iterare
+in modo ordinato, si può usare `sorted()` [5.6].
+
+Le liste possono essere estese con operazioni come l'aggiunta di
+elementi alla fine con `append()`, l'inserimento di elementi in una
+posizione specifica con `insert()`, e la rimozione di elementi con
+`pop()` o `del` [5.1.1][5.2].
+
+Le **List Comprehension** sono un modo conciso per creare liste basate
+su altre liste o iterabili, con la possibilità di includere
+condizioni. Sono particolarmente utili per creare nuove liste da
+esistenti in modo efficiente [5.1.3].
+
+Infine, Python supporta il confronto tra sequenze e altri tipi di
+dati, permettendo confronti lessicografici tra elementi di sequenze
+dello stesso tipo. Questo è utile per l'ordinamento e la comparazione
+di dati [5.8].
 
 ## Esercizi
 
@@ -379,19 +409,44 @@ spiegarmelo concisamente e utilizzando uno stile socratico?
 
 **llm**:
 
-L'algoritmo del "Bubble Sort" è noto per essere uno dei metodi di ordinamento più semplici. Come Socrate, posso guidarti attraverso il processo di comprensione di come funziona, usando domande per stimolare il pensiero critico.
-
-Immagina di avere una serie di oggetti, come per esempio delle palle, e ognuna di queste palle ha un peso diverso. Il tuo obiettivo è ordinare queste palle dal peso più leggero al peso più pesante. Come potresti fare?
-
-1. **Inizia con la prima pallina**: Se la pallina non è la più leggera, la scambi con la pallina accanto a lei che è più leggera. Continua a fare questo per tutta la serie.
-2. **Ripeti il processo**: Dopo aver scambiato tutte le palline adiacenti che non sono nell'ordine corretto, ripeti il processo, ma questa volta escludi l'ultima pallina che hai già messo in posizione corretta.
-3. **Continua fino a quando non devi più scambiare nessuna pallina**: Questo indica che tutte le palline sono ora ordinate dal peso più leggero al più pesante.
-
-Questo processo è esattamente come funziona il Bubble Sort. Ad ogni passaggio, l'algoritmo "bambina" gli elementi più pesanti (nel senso del valore più alto) verso il "fondo" dell'array. Ricorda, Socrate, che questo metodo non è il più efficiente per grandi insiemi di dati, ma è un ottimo punto di partenza per comprendere come funzionano gli algoritmi di ordinamento.
-
-Per illustrare meglio, immagina di avere un array di numeri: `[5, 3, 8, 4, 2, 6, 9]`. Dopo il primo passaggio, avrai `[3, 5, 4, 2, 6, 8, 9]`, dopo il secondo `[3, 4, 2, 5, 6, 8, 9]`, e così via, fino a quando l'array non è più ordinato, ovvero `[2, 3, 4, 5, 6, 8, 9]`.
-
-Ricorda, come Socrate amava sottolineare, la conoscenza è la chiave per capire meglio il mondo. Quindi, prova a implementare il Bubble Sort da solo e osserva come funziona con vari array di numeri. Questo ti aiuterà a cogliere meglio il concetto e a sviluppare una comprensione più profonda degli algoritmi di ordinamento.
+L'algoritmo del "Bubble Sort" è noto per essere uno dei metodi di
+ordinamento più semplici. Come Socrate, posso guidarti attraverso il
+processo di comprensione di come funziona, usando domande per
+stimolare il pensiero critico.
+
+Immagina di avere una serie di oggetti, come per esempio delle palle,
+e ognuna di queste palle ha un peso diverso. Il tuo obiettivo è
+ordinare queste palle dal peso più leggero al peso più pesante. Come
+potresti fare?
+
+1. **Inizia con la prima pallina**: Se la pallina non è la più
+   leggera, la scambi con la pallina accanto a lei che è più
+   leggera. Continua a fare questo per tutta la serie.
+2. **Ripeti il processo**: Dopo aver scambiato tutte le palline
+   adiacenti che non sono nell'ordine corretto, ripeti il processo, ma
+   questa volta escludi l'ultima pallina che hai già messo in
+   posizione corretta.
+3. **Continua fino a quando non devi più scambiare nessuna pallina**:
+   Questo indica che tutte le palline sono ora ordinate dal peso più
+   leggero al più pesante.
+
+Questo processo è esattamente come funziona il Bubble Sort. Ad ogni
+passaggio, l'algoritmo sposta gli elementi più pesanti (nel senso del
+valore più alto) verso il "fondo" dell'array. Ricorda, che questo
+metodo non è il più efficiente per grandi insiemi di dati, ma è un
+ottimo punto di partenza per comprendere come funzionano gli algoritmi
+di ordinamento.
+
+Per illustrare meglio, immagina di avere un array di numeri: `[5, 3,
+8, 4, 2, 6, 9]`. Dopo il primo passaggio, avrai `[3, 5, 4, 2, 6, 8,
+9]`, dopo il secondo `[3, 4, 2, 5, 6, 8, 9]`, e così via, fino a
+quando l'array non è più ordinato, ovvero `[2, 3, 4, 5, 6, 8, 9]`.
+
+Ricorda, come Socrate amava sottolineare, la conoscenza è la chiave
+per capire meglio il mondo. Quindi, prova a implementare il Bubble
+Sort da solo e osserva come funziona con vari array di numeri. Questo
+ti aiuterà a cogliere meglio il concetto e a sviluppare una
+comprensione più profonda degli algoritmi di ordinamento.
 
 **Io**: Ora proponimi una semplice implementazione in Python. Non
 usare funzioni di libreria.
@@ -415,3 +470,276 @@ arr = [64, 34, 25, 12, 22, 11, 90]
 bubbleSort(arr)
 print("Array ordinato:", arr)
 ```
+
+# Funzioni
+
+**Io**: Torniamo al nostro script originario, l'implentazione del
+cifrario di Cesare. Usa questo esempio per parlarmi delle funzioni in
+Python.
+
+```python
+def cesar_cipher(text, key):
+    result = ""
+    i =  0
+
+    while i < len(text):
+        char = text[i]
+
+        if char.isupper():
+            result += chr((ord(char) -  65 + key) %  26 +  65)
+        else:
+            result += chr((ord(char) -  97 + key) %  26 +  97)
+
+        i +=  1
+
+    return result
+
+text = input("Inserisci il testo da cifrare: ")
+key = int(input("Inserisci la chiave: "))
+
+print("Testo cifrato: ", cesar_cipher(text, key))
+```
+
+**llm**:
+
+Lo script Python fornito implementa un cifrario di Cesare, un metodo
+semplice di cifratura che sposta i caratteri del testo di un numero di
+posizioni determinato dalla chiave. Ecco una spiegazione sintetica
+sull'utilizzo delle funzioni in Python basata sullo script:
+
+- **Definizione della funzione**: La funzione `cesar_cipher` è
+  definita con la parola chiave `def`, seguita dal nome della funzione
+  e parentesi contenenti i parametri `text` e `key`. Questa funzione è
+  un blocco di codice che viene eseguito solo quando viene chiamata,
+  come spiegato in [Source 0] e [Source 1].
+
+- **Parametri della funzione**: La funzione accetta due parametri:
+  `text`, che è il testo da cifrare, e `key`, che è la chiave di
+  cifratura. Questi parametri sono passati alla funzione quando viene
+  chiamata, come indicato in [Source 1] e [Source 3].
+
+- **Corpo della funzione**: All'interno della funzione, viene
+  inizializzato un risultato vuoto (`result = ""`) e un indice `i`
+  a 0. Quindi, entro un ciclo `while`, la funzione itera su ogni
+  carattere del testo. Se il carattere è maiuscolo, viene cifrato
+  sottraendo 65 (valore ASCII di 'A'), aggiungendo la chiave, e poi
+  riportando il risultato nel range di valori ASCII di 'A' a 'Z'
+  utilizzando l'operatore modulo (`% 26`). Se il carattere è
+  minuscolo, viene cifrato in modo simile, ma utilizzando 97 (valore
+  ASCII di 'a') e 122 (valore ASCII di 'z') come base. Questo processo
+  di cifratura è specifico per il cifrario di Cesare e si basa
+  sull'uso della funzione `chr` per convertire i codici ASCII in
+  caratteri.
+
+- **Ritorno del risultato**: Alla fine del ciclo, la funzione
+  restituisce il risultato cifrato (`return result`). Questo vale per
+  tutte le funzioni in Python che devono restituire un valore; se non
+  viene specificato un valore di ritorno, la funzione restituisce
+  `None` di default, come descritto in [Source 3].
+
+- **Chiamata della funzione**: Dopo la definizione della funzione, il
+  codice richiede all'utente di inserire il testo da cifrare e la
+  chiave, utilizzando la funzione `input`. Questi valori vengono poi
+  passati alla funzione `cesar_cipher` per cifrare il testo. Infine,
+  il risultato cifrato viene stampato con `print`.
+
+Questo script illustra come definire, chiamare e utilizzare funzioni
+in Python per eseguire compiti specifici, come la cifratura di testo,
+permettendo di riutilizzare il codice e migliorare la leggibilità e la
+manutenibilità del programma.
+
+**Io**: Ci sono altri modi per passare argomenti ad una funzione?
+
+## Keyword arguments
+
+I "named arguments" o "keyword arguments" in Python sono un modo
+flessibile e potente per passare argomenti a una funzione, permettendo
+di specificare i valori in base al nome dell'argomento invece che alla
+posizione. Questo approccio può migliorare la leggibilità del codice e
+rendere il passaggio di argomenti più esplicito, specialmente quando
+una funzione ha molti parametri o quando gli argomenti non sono
+facilmente identificabili dalla loro posizione.
+
+### Che cosa sono i "named arguments"?
+
+I "named arguments" sono definiti passando i valori direttamente dopo
+il nome del parametro nella chiamata della funzione. Questo consente
+di omettere alcuni argomenti se hanno valori predefiniti nella
+definizione della funzione, e di passare gli argomenti in qualsiasi
+ordine, purché siano specificati per nome. Ad esempio:
+
+```python
+def my_function(a, b, c=0):
+    print(a, b, c)
+
+my_function(a=1, b=2) # c=0 perché non è specificato
+my_function(b=2, a=1, c=3) # Ordine arbitrario
+```
+
+### Utilizzo dei "named arguments"
+
+- **Chiarezza e flessibilità**: Passare argomenti per nome può rendere
+  il codice più leggibile e intuitivo, soprattutto quando una funzione
+  ha molti parametri. Permette di passare argomenti in qualsiasi
+  ordine, purché tutti i parametri obbligatori siano specificati.
+- **Argomenti opzionali**: I "named arguments" sono particolarmente
+  utili per gli argomenti opzionali, poiché permettono di ometterli se
+  non sono necessari o se si desidera utilizzare un valore
+  predefinito.
+- **Funzioni con molti parametri**: Per le funzioni con molti
+  parametri, i "named arguments" possono rendere il codice più
+  gestibile, evitando confusione su quale valore corrisponde a quale
+  parametro.
+
+### Esempi di utilizzo
+
+```python
+def print_person_info(name, age, city):
+    print(f"Name: {name}, Age: {age}, City: {city}")
+
+print_person_info(name="Alice", age=30, city="New York")
+```
+
+In questo esempio, `name`, `age`, e `city` sono argomenti
+"named". Questo approccio rende il codice più chiaro e meno propenso
+agli errori, specialmente quando si lavora con funzioni complesse o
+con molte variabili.
+
+**Io**: Produci un esempio di utilizzo dei keyword arguments partendo
+dallo script originario del cifrario di Cesare.
+
+**llm**:
+
+Per adattare lo script del cifrario di Cesare all'uso dei "keyword
+arguments" (o "named arguments"), modificheremo la funzione
+`cesar_cipher` per accettare gli argomenti in base al loro nome,
+invece che alla loro posizione. Questo approccio migliora la
+leggibilità e la flessibilità del codice, specialmente quando si
+lavora con funzioni che hanno molti parametri o quando si desidera
+passare argomenti in un ordine diverso da quello in cui sono stati
+definiti.
+
+Ecco come potrebbe apparire la funzione modificata:
+
+```python
+def cesar_cipher(text, key):
+    result = ""
+    i = 0
+
+    while i < len(text):
+        char = text[i]
+
+        if char.isupper():
+            result += chr((ord(char) - 65 + key) % 26 + 65)
+        else:
+            result += chr((ord(char) - 97 + key) % 26 + 97)
+
+        i += 1
+
+    return result
+
+# Chiamata della funzione utilizzando keyword arguments
+text = "Inserisci il testo da cifrare"
+key = 3
+
+print("Testo cifrato: ", cesar_cipher(text=text, key=key))
+```
+
+In questo esempio, la chiamata alla funzione `cesar_cipher` utilizza
+"keyword arguments" specificando `text=text` e `key=key`. Questo
+approccio rende il codice più chiaro e esplicito su quale valore
+corrisponde a quale parametro, facilitando la lettura e la
+manutenzione del codice.
+
+I "keyword arguments" sono particolarmente utili quando si hanno
+funzioni con molti parametri, consentendo di passare gli argomenti in
+qualsiasi ordine e di specificare solo quelli che si desidera
+modificare, mantenendo gli altri ai loro valori predefiniti. Questo
+approccio è particolarmente utile in Python, dove la flessibilità
+nella definizione e chiamata delle funzioni è una delle sue
+caratteristiche principali.
+
+### Considerazioni aggiuntive
+
+- **Argomenti predefiniti**: È possibile definire valori predefiniti
+  per alcuni parametri, consentendo di ometterli quando si chiama la
+  funzione.
+- **Flessibilità**: I "named arguments" possono essere combinati con
+  altri tipi di argomenti, come gli argomenti posizionali (`*args`) e
+  gli argomenti di lunghezza variabile (`**kwargs`), per creare
+  funzioni estremamente flessibili e potenti.
+
+In sintesi, i "named arguments" in Python offrono una potente e
+flessibile modalità per passare argomenti a una funzione, migliorando
+la leggibilità e la manutenibilità del codice.
+
+# Semplici casi d'uso reali
+
+In questa sezione verranno presentati e discussi alcuni script che
+risolvono problematiche realistiche nell'ambito dell'amministrazione
+di sistemi GNU/Linux.
+
+## Backup
+
+**Io**: Proponimi un semplice script per effettuare il backup di una cartella.
+
+Basandomi sulle informazioni fornite, ecco un semplice script Python
+che può essere utile per l'amministrazione di un sistema Linux. Questo
+script utilizzerà il modulo `os` per eseguire comandi di sistema e il
+modulo `datetime` per ottenere informazioni sulla data e l'ora,
+rendendolo un esempio pratico di come Python può essere utilizzato per
+automatizzare compiti di amministrazione di sistema.
+
+Lo script mostrerà l'utilizzo di Python per eseguire un backup di un
+file specifico e stampare il risultato, insieme alla data e l'ora del
+backup, rendendolo utile per la gestione dei file e l'automazione dei
+compiti di amministrazione.
+
+```python
+import os
+import datetime
+
+def backup_file(file_path, backup_dir):
+    """
+    Esegue il backup di un file specificato e lo salva in una directory di backup.
+
+    Parametri:
+    file_path (str): Percorso del file da eseguire il backup.
+    backup_dir (str): Percorso della directory dove salvare il backup.
+
+    Ritorna:
+    None
+    """
+    # Controlla se la directory di backup esiste
+    if not os.path.exists(backup_dir):
+        os.makedirs(backup_dir)
+
+    # Costruisce il percorso del file di backup
+    backup_file_path = os.path.join(backup_dir, os.path.basename(file_path))
+
+    # Esegue il backup del file
+    os.system(f"cp {file_path} {backup_file_path}")
+
+    # Stampa informazioni sul backup
+    print(f"Backup eseguito il {datetime.datetime.now()} per il file {file_path}")
+    print(f"File di backup salvato in: {backup_file_path}")
+
+# Esempio di utilizzo
+file_to_backup = "/path/to/your/file.txt"
+backup_directory = "/path/to/backup/directory"
+backup_file(file_to_backup, backup_directory)
+```
+
+Questo script definisce una funzione `backup_file` che accetta due
+argomenti: `file_path` per il percorso del file da eseguire il backup
+e `backup_dir` per la directory dove salvare il backup. Utilizza il
+modulo `os` per verificare l'esistenza della directory di backup e per
+eseguire il comando di copia (`cp`) per il backup del file. Inoltre,
+utilizza il modulo `datetime` per ottenere la data e l'ora corrente,
+stampando queste informazioni insieme al risultato del backup.
+
+Questo esempio dimostra come Python può essere utilizzato per eseguire
+compiti di amministrazione di sistema, come la gestione dei file e
+l'automazione di compiti come il backup dei file, rendendo il processo
+più efficiente e gestibile.
+

BIN
pdf/README.pdf


BIN
pdf/introduzione_al_coding.pdf


+ 34 - 0
scripts/backup.py

@@ -0,0 +1,34 @@
+#!/bin/python
+
+import os
+import datetime
+
+def backup_file(file_path=".", backup_dir="/tmp"):
+    """
+    Esegue il backup di un file specificato e lo salva in una directory di backup.
+
+    Parametri:
+    file_path (str): Percorso del file da eseguire il backup.
+    backup_dir (str): Percorso della directory dove salvare il backup.
+
+    Ritorna:
+    None
+    """
+    # Controlla se la directory di backup esiste
+    if not os.path.exists(backup_dir):
+        os.makedirs(backup_dir)
+
+    # Costruisce il percorso del file di backup
+    backup_file_path = os.path.join(backup_dir, os.path.basename(file_path))
+
+    # Esegue il backup del file
+    os.system(f"cp -r {file_path} {backup_file_path}")
+
+    # Stampa informazioni sul backup
+    print(f"Backup eseguito il {datetime.datetime.now()} per il file {file_path}")
+    print(f"File di backup salvato in: {backup_file_path}")
+
+# Esempio di utilizzo
+file_to_backup = "."
+backup_directory = "/tmp/backup"
+backup_file(file_to_backup, backup_directory)

+ 21 - 0
scripts/cesar.py

@@ -0,0 +1,21 @@
+def cesar_cipher(text, key=3):
+    result = ""
+    i = 0
+
+    while i < len(text):
+        char = text[i]
+
+        if char.isupper():
+            result += chr((ord(char) - 65 + key) % 26 + 65)
+        else:
+            result += chr((ord(char) - 97 + key) % 26 + 97)
+
+        i += 1
+
+    return result
+
+# Chiamata della funzione utilizzando keyword arguments
+text = "Inserisci il testo da cifrare"
+key = 3
+
+print("Testo cifrato: ", cesar_cipher(text=text))