Generare Codice con il Codice: Un Esempio Pratico con Python e Regex

Cerca:

Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors
Generazione di codice Python con Regex

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:

Forse potrebbe interessarti anche:  Test di Probabilità Avanzata per Data Analyst: Domina i Concetti Hero per l'AI e il Machine Learning

=== 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

  1. Struttura del Codice:

    • La classe SimpleCodeGenerator è il cuore del programma. Contiene un dizionario patterns che associa espressioni regolari a funzioni di generazione del codice.
    • Il metodo generate_code prende 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_reader e _generate_for_loop sono responsabili della generazione del codice per specifiche richieste.
  2. 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 regex 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+)' corrisponde a richieste come “Crea una funzione che calcola la somma di numero1 e numero2”.
    • La funzione re.search viene 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.
  3. 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_function utilizza i nomi dei parametri estratti dalla richiesta per creare una funzione che calcola la somma di quei parametri.
Forse potrebbe interessarti anche:  Pandas Python: Tutorial Completo per l'Analisi e la Manipolazione dei Dati

regex

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:

  1. 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.
  2. 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”.
  3. 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.
Forse potrebbe interessarti anche:  ANOVA: 6 Esercizi Pratici per Comprendere l'Analisi della Varianza (con Codice Python)

Utilizzo delle Regex nel Codice

  1. Definizione dei Pattern: Le regex sono definite come stringhe “raw” (precedute da r) nel dizionario self.patterns. Questo impedisce l’interpretazione dei caratteri di escape da parte di Python.
  2. Ricerca delle Corrispondenze: La funzione re.search(pattern, request) cerca una corrispondenza tra la regex pattern e la richiesta dell’utente request.
  3. Estrazione dei Gruppi: Se viene trovata una corrispondenza, la funzione match.groups() restituisce una tupla contenente i gruppi catturati dalla regex.
  4. 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.

Pubblicità