Parliamo

project-cherry.dev

Intermedio13 min

Moduli e Pacchetti

Organizza il progetto dello studio legale in moduli Python strutturati, con dipendenze gestite e ambienti virtuali isolati.

Moduli e Pacchetti

Il codice dello studio legale dell'Avv. Rossi sta crescendo: clienti, pratiche, fatture, validazione. Tenere tutto in un unico file diventa ingestibile. Python risolve questo problema con i moduli (singoli file .py) e i pacchetti (cartelle con un file __init__.py). Organizzare bene il codice oggi significa risparmiare ore di debug domani.

Il primo modulo: fatturazione.py

Un modulo è semplicemente un file Python che contiene funzioni, classi o variabili. Puoi importarlo da altri file per riutilizzare il codice senza copia-incolla.

python
# fatturazione.py - Modulo per la fatturazione dello studio legale

ALIQUOTA_IVA = 22  # percentuale IVA standard

def calcola_netto(ore_lavorate, tariffa_oraria):
    """Calcola l'importo netto di una pratica."""
    return ore_lavorate * tariffa_oraria

def calcola_totale(importo_netto, aliquota=ALIQUOTA_IVA):
    """Aggiunge l'IVA all'importo netto."""
    iva = importo_netto * aliquota / 100
    return importo_netto + iva

def formatta_importo(valore):
    """Formatta un importo in formato europeo."""
    return f"{valore:,.2f} EUR".replace(",", ".")

# --- Uso da un altro file ---
# main.py
from fatturazione import calcola_netto, calcola_totale, formatta_importo

netto = calcola_netto(ore_lavorate=12, tariffa_oraria=150)
totale = calcola_totale(netto)
print(f"Totale fattura: {formatta_importo(totale)}")
# Totale fattura: 2.196,00 EUR  (nota: output semplificato)

Puoi importare funzioni singole con from modulo import funzione, oppure il modulo intero con import modulo e usare modulo.funzione().

Struttura di un progetto reale

Quando il progetto ha più responsabilità (clienti, pratiche, fatture), ogni area diventa un modulo separato dentro un pacchetto.

python
# Struttura del progetto studio_legale/
#
# studio_legale/
# ├── __init__.py          # Rende la cartella un pacchetto Python
# ├── clienti.py           # Classe Cliente, ClientePrivato, ClienteAziendale
# ├── pratiche.py          # Classe Pratica, gestione ore
# ├── fatture.py           # Classe Fattura, calcolo IVA
# ├── validazione.py       # Validazione CF, importi, date
# └── esporta.py           # Export CSV e PDF
#
# main.py                    # Punto di ingresso dell'applicazione
# requirements.txt           # Dipendenze del progetto
# .venv/                     # Ambiente virtuale (NON va nel repository)

# __init__.py - Espone le classi principali del pacchetto
from .clienti import Cliente, ClientePrivato, ClienteAziendale
from .pratiche import Pratica
from .fatture import Fattura

# main.py - Importa dal pacchetto in modo pulito
from studio_legale import Cliente, Pratica, Fattura

cliente = Cliente("Laura", "Verdi", "VRDLRA85M41H501Z")
pratica = Pratica("2024-001", cliente, "Contenzioso civile")
fattura = Fattura(pratica)
print(fattura)

Il file __init__.py definisce cosa viene esportato dal pacchetto. Il punto (.) in from .clienti import indica un import relativo, cioè dalla stessa cartella.

Gestire dipendenze con pip

Il progetto potrebbe dover comunicare con API esterne, ad esempio il portale del tribunale. Per questo servono librerie di terze parti, installabili con pip.

python
# Installare una libreria (da terminale)
# pip install requests

import requests

def cerca_pratica_tribunale(numero_ruolo):
    """Interroga l'API del tribunale per ottenere lo stato di una pratica."""
    try:
        risposta = requests.get(
            f"https://api.tribunale.example.it/pratiche/{numero_ruolo}",
            timeout=10
        )
        risposta.raise_for_status()  # lancia eccezione se status != 200
        return risposta.json()
    except requests.ConnectionError:
        print("Impossibile raggiungere il server del tribunale")
        return None
    except requests.Timeout:
        print("Il server non ha risposto entro 10 secondi")
        return None

# Salvare tutte le dipendenze del progetto
# pip freeze > requirements.txt
#
# Contenuto tipico di requirements.txt:
# requests==2.31.0
# python-dateutil==2.8.2

Il file requirements.txt elenca tutte le dipendenze con le versioni esatte, così chiunque può ricreare lo stesso ambiente.

Ambienti virtuali: isolare il progetto

Ogni progetto Python dovrebbe avere il proprio ambiente virtuale: uno spazio isolato dove installare le dipendenze senza interferire con altri progetti o con il Python di sistema.

python
# Creare un ambiente virtuale nella cartella del progetto
# python -m venv .venv

# Attivare l'ambiente virtuale
# Linux/Mac:   source .venv/bin/activate
# Windows:     .venv\Scripts\activate

# Quando l'ambiente è attivo, il prompt cambia:
# (.venv) \$ pip install requests
# (.venv) \$ pip freeze > requirements.txt

# Ricreare l'ambiente da requirements.txt (ad esempio su un nuovo computer)
# python -m venv .venv
# source .venv/bin/activate
# pip install -r requirements.txt

# Disattivare l'ambiente virtuale
# deactivate

Il pattern __name__ == "__main__"

Questo pattern distingue tra quando un file viene eseguito direttamente e quando viene importato come modulo. È fondamentale per scrivere codice riutilizzabile.

python
# fatturazione.py

ALIQUOTA_IVA = 22

def calcola_totale(netto, aliquota=ALIQUOTA_IVA):
    return netto + (netto * aliquota / 100)

# Questo blocco si esegue SOLO se lanci "python fatturazione.py"
# NON si esegue quando fai "from fatturazione import calcola_totale"
if __name__ == "__main__":
    # Codice di test rapido
    print("=== Test modulo fatturazione ===")
    test_netto = 1000.0
    test_totale = calcola_totale(test_netto)
    print(f"Netto: {test_netto:.2f} EUR")
    print(f"Totale con IVA: {test_totale:.2f} EUR")
    print("Test superato!" if test_totale == 1220.0 else "ERRORE nel calcolo!")

Senza questo pattern, il codice di test verrebbe eseguito ogni volta che qualcuno importa il modulo, causando output indesiderati e rallentamenti.

Da ricordare

  • Un modulo è un file .py, un pacchetto è una cartella con __init__.py
  • Usa from modulo import funzione per importare solo ciò che serve, evitando import *
  • Crea sempre un ambiente virtuale per ogni progetto con python -m venv .venv
  • Mantieni requirements.txt aggiornato con pip freeze > requirements.txt
  • Il pattern if __name__ == "__main__" separa codice riutilizzabile da codice di test
  • La struttura del progetto deve rispecchiare la logica del dominio: un modulo per responsabilità