Introduzione
Nel mondo della programmazione, l’idea di “codice che genera codice” può sembrare astratta, ma è una tecnica potente con molte applicazioni pratiche. In questo articolo, esploreremo un esempio didattico di un semplice generatore di codice Python, che utilizza le espressioni regolari (regex) per analizzare le richieste degli utenti e generare il codice Python corrispondente.
Obiettivo del Codice
L’obiettivo principale di questo codice è dimostrare come sia possibile creare un programma che interpreta il linguaggio naturale (in forma semplificata) e lo traduce in codice eseguibile. Questo tipo di programma può essere utilizzato per automatizzare la generazione di codice boilerplate, creare strumenti di prototipazione rapida o persino sviluppare linguaggi di programmazione specifici per un dominio.
import re
import random
class SimpleCodeGenerator:
"""
Generatore semplice di codice Python basato su pattern matching e template.
Questo codice rappresenta un esempio didattico di "codice che genera codice".
"""
def __init__(self):
# Dizionario di pattern: ogni pattern è associato a una funzione che genera codice
self.patterns = {
r'crea\s+una\s+funzione\s+che\s+(?:calcola|restituisce|ritorna)\s+(?:la\s+)?somma\s+di\s+(\w+)\s+(?:e|con)\s+(\w+)': self._generate_sum_function,
r'crea\s+una\s+lista\s+di\s+(\d+)\s+numeri\s+(?:interi\s+)?(?:casuali|random)': self._generate_random_list,
r'crea\s+una\s+classe\s+(?:chiamata\s+)?(\w+)(?:\s+con\s+(?:gli\s+)?attributi\s+(.+))?': self._generate_class,
r'scrivi\s+(?:un\s+)?codice\s+per\s+leggere\s+(?:un\s+)?file\s+(?:chiamato\s+)?[\'"]?(\w+\.?\w*)[\'"]?': self._generate_file_reader,
r'crea\s+(?:un\s+)?ciclo\s+for\s+(?:che\s+)?(?:itera|scorre)\s+(?:su|attraverso)\s+(?:una\s+)?lista\s+(?:chiamata\s+)?(\w+)': self._generate_for_loop
}
def generate_code(self, request):
"""
Analizza la richiesta dell'utente e genera il codice corrispondente.
Questo processo avviene attraverso l'utilizzo delle espressioni regolari (regex)
che permettono di identificare il tipo di codice richiesto.
"""
request = request.lower().strip()
for pattern, generator in self.patterns.items():
match = re.search(pattern, request)
if match:
return generator(*match.groups())
return "# Mi dispiace, non ho capito la tua richiesta. Prova con una richiesta più semplice o diversa."
def _generate_sum_function(self, param1, param2):
return f"""def somma_{param1}_{param2}({param1}, {param2}):
return {param1} + {param2}
print(somma_{param1}_{param2}(5, 10))"""
def _generate_random_list(self, count):
count = int(count)
return f"""import random
numeri_casuali = [random.randint(1, 100) for _ in range({count})]
print(numeri_casuali)"""
def _generate_class(self, class_name, attributes=None):
if attributes:
attrs = re.split(r',\s*|\s+e\s+', attributes)
attr_code = "\n".join([f" self.{attr} = {attr}" for attr in attrs])
init_params = ", ".join(attrs)
return f"""class {class_name}:
def __init__(self, {init_params}):
{attr_code}
print({class_name}({', '.join(['1'] * len(attrs))}))"""
else:
return f"""class {class_name}:
def __init__(self):
pass
print({class_name}())"""
def _generate_file_reader(self, filename):
return f"""with open('{filename}', 'r', encoding='utf-8') as file:
print(file.read())"""
def _generate_for_loop(self, list_name):
return f"""{list_name} = [1, 2, 3, 4, 5]
for item in {list_name}:
print(item)"""
generatore = SimpleCodeGenerator()
esempi = [
"Crea una funzione che calcola la somma di numero1 e numero2",
"Crea una lista di 10 numeri casuali",
"Crea una classe chiamata Persona con gli attributi nome, età e indirizzo",
"Scrivi un codice per leggere un file chiamato 'dati.csv'",
"Crea un ciclo for che itera su una lista chiamata elementi"
]
for i, esempio in enumerate(esempi, 1):
print(f"\n\n=== ESEMPIO {i}: {esempio} ===\n")
print(generatore.generate_code(esempio))
Output:
=== ESEMPIO 1: Crea una funzione che calcola la somma di numero1 e numero2 ===
def somma_numero1_numero2(numero1, numero2):
return numero1 + numero2
print(somma_numero1_numero2(5, 10))
=== ESEMPIO 2: Crea una lista di 10 numeri casuali ===
import random
numeri_casuali = [random.randint(1, 100) for _ in range(10)]
print(numeri_casuali)
=== ESEMPIO 3: Crea una classe chiamata Persona con gli attributi nome, età e indirizzo ===
class persona:
def __init__(self, nome, età, indirizzo):
self.nome = nome
self.età = età
self.indirizzo = indirizzo
print(persona(1, 1, 1))
=== ESEMPIO 4: Scrivi un codice per leggere un file chiamato ‘dati.csv’ ===
with open(‘dati.csv’, ‘r’, encoding=’utf-8′) as file:
print(file.read())
=== ESEMPIO 5: Crea un ciclo for che itera su una lista chiamata elementi ===
elementi = [1, 2, 3, 4, 5]
for item in elementi:
print(item)
Spiegazione Passo a Passo
-
Struttura del Codice:
- La classe
SimpleCodeGeneratorè il cuore del programma. Contiene un dizionariopatternsche associa espressioni regolari a funzioni di generazione del codice. - Il metodo
generate_codeprende una richiesta dell’utente come input, la analizza utilizzando le regex e restituisce il codice generato. - I metodi
_generate_sum_function,_generate_random_list,_generate_class,_generate_file_readere_generate_for_loopsono responsabili della generazione del codice per specifiche richieste.
- La classe
-
Utilizzo delle Espressioni Regolari (Regex):
- Le regex sono fondamentali per il funzionamento del generatore di codice. Permettono di definire pattern di testo che possono essere utilizzati per identificare e estrarre informazioni dalle richieste degli utenti.
- Nel dizionario
patterns, ogni chiave è una regex che corrisponde a un tipo specifico di richiesta. Ad esempio, la regexr'crea\s+una\s+funzione\s+che\s+(?:calcola|restituisce|ritorna)\s+(?:la\s+)?somma\s+di\s+(\w+)\s+(?:e|con)\s+(\w+)'corrisponde a richieste come “Crea una funzione che calcola la somma di numero1 e numero2”. - La funzione
re.searchviene utilizzata per cercare una corrispondenza tra la regex e la richiesta dell’utente. Se viene trovata una corrispondenza, i gruppi catturati dalla regex vengono passati alla funzione di generazione del codice corrispondente. \s+corrisponde ad uno o più spazi bianchi.(?:calcola|restituisce|ritorna)è un gruppo di non cattura, cioè cerca una delle parole inserite nel gruppo, ma non la salva come risultato della ricerca.(\w+)corrisponde ad una o più parole e le salva come risultato della ricerca.
-
Generazione del Codice:
- Le funzioni di generazione del codice utilizzano i gruppi catturati dalle regex per creare stringhe di codice Python.
- Ad esempio, la funzione
_generate_sum_functionutilizza i nomi dei parametri estratti dalla richiesta per creare una funzione che calcola la somma di quei parametri.

Cosa sono le Regex e a cosa servono
Le regex sono sequenze di caratteri che definiscono un pattern di ricerca.
Sono uno strumento potente per la manipolazione di stringhe, consentendo di:
- Ricercare specifiche sequenze di caratteri in un testo.
- Estrarre parti di testo che corrispondono a un determinato pattern.
- Sostituire parti di testo con altre stringhe.
- Validare il formato di una stringa.
Analisi delle Regex nel Codice
Nel nostro codice, le regex vengono utilizzate per definire i pattern di ricerca delle diverse richieste che l’utente può fare.
Analizziamo alcune delle regex utilizzate:
-
r'crea\s+una\s+funzione\s+che\s+(?:calcola|restituisce|ritorna)\s+(?:la\s+)?somma\s+di\s+(\w+)\s+(?:e|con)\s+(\w+)':crea\s+una\s+funzione\s+che\s+: Corrisponde alla sequenza letterale “crea una funzione che”, seguita da uno o più spazi bianchi (\s+).(?:calcola|restituisce|ritorna): Questo è un gruppo di “non cattura” che corrisponde a una delle parole “calcola”, “restituisce” o “ritorna”. Il(?:...)indica che il gruppo non deve essere catturato come risultato della ricerca.(?:la\s+)?: Corrisponde opzionalmente alla sequenza “la” seguita da uno o più spazi bianchi. Il?rende il gruppo opzionale.(\w+): Questo è un gruppo di “cattura” che corrisponde a una o più parole (\w+). Le parentesi tonde(...)indicano che il testo corrispondente a questo pattern deve essere catturato e reso disponibile come risultato della ricerca. In questo caso, cattura il nome del primo parametro della funzione.(?:e|con)\s+: Corrisponde alla parola “e” o “con”, seguita da uno o più spazi bianchi.(\w+): Cattura il nome del secondo parametro della funzione.
-
r'crea\s+una\s+lista\s+di\s+(\d+)\s+numeri\s+(?:interi\s+)?(?:casuali|random)':crea\s+una\s+lista\s+di\s+: Corrisponde alla sequenza letterale “crea una lista di”, seguita da uno o più spazi bianchi.(\d+): Cattura una o più cifre numeriche (\d+), che rappresentano il numero di elementi della lista.numeri\s+(?:interi\s+)?(?:casuali|random): Corrisponde alla sequenza “numeri”, seguita da spazi bianchi, dalla parola opzionale “interi” e dalla parola “casuali” o “random”.
-
r'crea\s+una\s+classe\s+(?:chiamata\s+)?(\w+)(?:\s+con\s+(?:gli\s+)?attributi\s+(.+))?':crea\s+una\s+classe\s+(?:chiamata\s+)?: Corrisponde alla sequenza letterale “crea una classe”, seguita opzionalmente dalla parola “chiamata”.(\w+): Cattura il nome della classe.(?:\s+con\s+(?:gli\s+)?attributi\s+(.+))?: Corrisponde opzionalmente alla sequenza “con attributi”, seguita da uno o più caratteri qualsiasi (.+), che rappresentano gli attributi della classe.
Utilizzo delle Regex nel Codice
- Definizione dei Pattern: Le regex sono definite come stringhe “raw” (precedute da
r) nel dizionarioself.patterns. Questo impedisce l’interpretazione dei caratteri di escape da parte di Python. - Ricerca delle Corrispondenze: La funzione
re.search(pattern, request)cerca una corrispondenza tra la regexpatterne la richiesta dell’utenterequest. - Estrazione dei Gruppi: Se viene trovata una corrispondenza, la funzione
match.groups()restituisce una tupla contenente i gruppi catturati dalla regex. - Generazione del Codice: I gruppi catturati vengono passati alla funzione di generazione del codice corrispondente, che li utilizza per creare il codice Python.
Vantaggi dell’Utilizzo delle Regex
- Flessibilità: Le regex consentono di definire pattern di ricerca complessi e flessibili.
- Potenza: Le regex sono uno strumento potente per la manipolazione di stringhe.
- Conciseness: Le regex consentono di esprimere pattern di ricerca in modo conciso.
Conclusione
Questo esempio dimostra come le regex possano essere utilizzate per creare programmi che interpretano e generano codice. Sebbene questo generatore di codice sia semplice, i principi alla base del suo funzionamento possono essere applicati a problemi più complessi.





