1. Home
  2. iThink
  3. Programmazione per Ragazzi
  4. Moduli e librerie standard di Python
Programmazione per Ragazzi Divento Programmatore · Capitolo 6

Moduli e librerie standard di Python

Codice Python sullo schermo di un computer
Foto: JohnsonMartin · Pixabay · Licenza dei contenuti Pixabay

Divento Programmatore — Capitolo 6: Moduli e librerie standard

Hai imparato a scrivere funzioni (Cap. 4) e gestire dati (Cap. 5). Ora impari a organizzare il codice in file riutilizzabili e usare la batteria inclusa di Python: centinaia di moduli pronti all'uso.

Cosa imparerai

| Concetto | Descrizione | | ---------- | ------------- | | Modulo | File .py con funzioni/classi/variabili | | import | Carica modulo nel namespace | | Standard Library | Moduli inclusi in Python (batterie incluse) | | random | Numeri casuali per giochi | | time | Timing, sleep, misurazione prestazioni | | math | Funzioni matematiche avanzate | | pip | Installa pacchetti terze parti (PyPI) |


1. Cos'è un modulo?

Un modulo è semplicemente un file Python (es. utilita.py). Lo importi per usare ciò che contiene.

progetto/
├── main.py          # Il tuo script principale
├── utilita.py       # Tuo modulo personale
└── gioco/
    ├── __init__.py  # Rende 'gioco' un package
    ├── nemici.py
    └── armi.py

2. Import: le forme principali

# 1. Importa tutto il modulo (namespace: modulo.nome)
import math
print(math.pi)
print(math.sqrt(16))

# 2. Importa nomi specifici (namespace diretto)
from math import pi, sqrt, sin
print(pi)
print(sqrt(16))

# 3. Importa con alias (evita conflitti nomi)
import random as rnd
print(rnd.randint(1, 6))

# 4. Importa tutto (⚠️ SCONSIGLIATO: inquina namespace)
from math import *
print(pi)  # Funziona, ma da dove viene pi?

Best practice: Usa forma 1 o 2. Forma 3 per moduli con nomi lunghi (numpy as np, pandas as pd).


3. La Standard Library: i "must" per i giochi

random — Casualità controllata

import random

# Interi
random.randint(1, 6)        # 1-6 inclusi (dado)
random.randrange(1, 7)      # 1-6 (stop escluso)
random.randrange(0, 101, 2) # Pari 0-100

# Float
random.random()             # 0.0 - 1.0
random.uniform(1.5, 5.5)    # Float in range

# Scelte da sequenza
random.choice(["rosso", "blu", "verde"])  # Un elemento
random.choices([1,2,3], k=5)              # Lista 5 elementi (con ripetizioni)
random.sample(range(1, 50), 6)            # 6 unici (senza ripetizioni) - tipo SuperEnalotto

# Mescola IN PLACE
carte = list(range(52))
random.shuffle(carte)

# Seed per riproducibilità (test, debug)
random.seed(42)
print(random.randint(1, 10))  # Sempre stesso "casuale"

Sicurezza: random non è crittografico. Per password e token usa il modulo secrets.

time — Tempo e attese

import time

# Timestamp attuale (secondi da epoch 1970)
now = time.time()           # float: 1703000000.123456

# Sleep (pausa esecuzione)
time.sleep(1)               # 1 secondo
time.sleep(0.5)             # 500 ms

# Misurare durata codice (alta precisione)
start = time.perf_counter()
# ... codice da misurare ...
end = time.perf_counter()
print(f"Durata: {end - start:.4f} secondi")

# Formattazione leggibile
print(time.ctime())         # 'Mon Dec 18 10:30:45 2023'
print(time.strftime("%Y-%m-%d %H:%M:%S"))  # '2023-12-18 10:30:45'

math — Matematica avanzata

import math

# Costanti
math.pi          # 3.141592653589793
math.e           # 2.718281828459045
math.tau         # 2*pi = 6.283185307179586

# Potenze e radici
math.sqrt(16)    # 4.0
math.pow(2, 10)  # 1024.0 (float)
2 ** 10          # 1024 (int, preferibile)

# Trigonometria (argomenti in RADIANTI)
math.sin(math.pi / 2)   # 1.0
math.cos(0)             # 1.0
math.radians(180)       # pi (gradi → radianti)
math.degrees(math.pi)   # 180.0 (radianti → gradi)

# Logaritmi
math.log(100, 10)   # 2.0 (base 10)
math.log(100)       # ln(100) (base e)
math.log10(100)     # 2.0
math.log2(8)        # 3.0

# Arrotondamenti
math.ceil(3.2)    # 4 (su)
math.floor(3.8)   # 3 (giù)
math.trunc(3.8)   # 3 (taglia decimali)
round(3.5)        # 4 (banker's rounding)

# Utilità
math.hypot(3, 4)      # 5.0 (ipotenusa: sqrt(x²+y²))
math.dist((0,0), (3,4)) # 5.0 (distanza 2D, Py 3.8+)
math.gcd(48, 18)      # 6 (mcd)
math.lcm(4, 6)        # 12 (mcm, Py 3.9+)

datetime — Date e orari (oggetti, non stringhe)

from datetime import datetime, timedelta, date

now = datetime.now()           # 2023-12-18 10:30:45.123456
today = date.today()           # 2023-12-18

# Formattazione
print(now.strftime("%d/%m/%Y %H:%M"))  # 18/12/2023 10:30

# Parsing
dt = datetime.strptime("25/12/2023", "%d/%m/%Y")

# Aritmetica date
domani = today + timedelta(days=1)
tra_un_ora = now + timedelta(hours=1)
diff = domani - today  # timedelta(days=1)

os, sys, pathlib — Sistema (anticipazione)

import os
import sys
from pathlib import Path

# Path moderni (pathlib, Py 3.4+)
base = Path(__file__).parent
file = base / "dati" / "salvataggio.json"
file.parent.mkdir(parents=True, exist_ok=True)  # Crea cartelle

# Variabili ambiente
os.getenv("HOME")           # Path home utente
os.environ.get("DEBUG")     # Legge env var

# Info sistema
sys.platform                # 'linux', 'darwin', 'win32'
sys.version                 # Versione Python

4. Creare i tuoi moduli

File: matematica_gioco.py

"""Utilità matematiche per giochi 2D."""

import math
from typing import Tuple

# Costanti di modulo (convenzione: MAIUSCOLO)
GRAVITA = 9.81
GRADI_IN_RADIANTI = math.pi / 180

def distanza(p1: Tuple[float, float], p2: Tuple[float, float]) -> float:
    """Distanza euclidea tra due punti (x, y)."""
    return math.hypot(p2[0] - p1[0], p2[1] - p1[1])

def angolo_verso(origine: Tuple[float, float], 
                 destinazione: Tuple[float, float]) -> float:
    """Angolo in gradi da origine a destinazione (0=est, 90=nord)."""
    dx = destinazione[0] - origine[0]
    dy = destinazione[1] - origine[1]
    return math.degrees(math.atan2(dy, dx))

def muovi_verso(pos: Tuple[float, float], 
                angolo_gradi: float, 
                velocita: float) -> Tuple[float, float]:
    """Nuova posizione muovendosi verso angolo con velocità data."""
    rad = angolo_gradi * GRADI_IN_RADIANTI
    return (pos[0] + math.cos(rad) * velocita,
            pos[1] + math.sin(rad) * velocita)

# Codice eseguibile solo se lancio diretto: python matematica_gioco.py
if __name__ == "__main__":
    # Test rapido / demo
    p1 = (0, 0)
    p2 = (10, 10)
    print(f"Distanza: {distanza(p1, p2):.2f}")
    print(f"Angolo: {angolo_verso(p1, p2):.1f}°")
    print(f"Muovi 5 unità: {muovi_verso(p1, 45, 5)}")

File: main.py (usa il modulo)

import matematica_gioco as mg

player = (100, 100)
target = (200, 150)

ang = mg.angolo_verso(player, target)
dist = mg.distanza(player, target)
new_pos = mg.muovi_verso(player, ang, 10)

print(f"Angolo: {ang:.1f}°, Distanza: {dist:.1f}, Nuova pos: {new_pos}")

5. __name__ == "__main__": pattern fondamentale

# mio_modulo.py

def funzione_utile():
    return "Utile!"

def _privata():           # Convenzione: _prefix = interno
    return "Non importare"

# Questo blocco gira SOLO se: python mio_modulo.py
# NON gira se: import mio_modulo
if __name__ == "__main__":
    print("Test modulo:")
    print(funzione_utile())
    # Test, demo, CLI entry point qui

Perché serve:

  • Permette di usare il file come script E come modulo
  • Test automatici (pytest importa, non esegue main)
  • Entry point CLI (python -m mio_pacchetto)

6. Package: cartelle con __init__.py

gioco/
├── __init__.py          # Inizializzazione package
├── core/
│   ├── __init__.py
│   ├── motore.py
│   └── entita.py
├── sistemi/
│   ├── __init__.py
│   ├── combattimento.py
│   └── inventario.py
└── ui/
    ├── __init__.py
    └── hud.py

gioco/__init__.py (esporta API pubblica):

"""Gioco RPG - Package principale."""

from .core.motore import MotoreGioco
from .sistemi.combattimento import Combattimento
from .sistemi.inventario import Inventario

__version__ = "1.0.0"
__all__ = ["MotoreGioco", "Combattimento", "Inventario"]

Uso:

from gioco import MotoreGioco, Inventario
from gioco.sistemi.combattimento import Combattimento

7. Pacchetti esterni: pip e PyPI

Installazione

# Terminale (non dentro Python!)
pip install pygame          # Libreria giochi 2D
pip install requests        # HTTP client
pip install pillow          # Immagini
pip install numpy           # Array numerici (base per ML/grafica)

requirements.txt (condividi dipendenze)

pygame>=2.5.0
requests>=2.31.0
pillow>=10.0.0
pip install -r requirements.txt  # Installa tutto
pip freeze > requirements.txt    # Genera da ambiente attuale

Virtual environments (best practice)

python -m venv venv        # Crea ambiente isolato
source venv/bin/activate   # Linux/macOS
venv\Scripts\activate      # Windows
pip install pygame         # Installa solo qui
deactivate                 # Esci

Per ragazzi: Su Thonny → Tools → Manage packages → installa lì. Thonny gestisce venv automatico.


8. Script completo: Toolkit gioco con moduli

toolkit_gioco/__init__.py

"""Toolkit base per giochi 2D."""
from .vettore import Vettore2D
from .timer import Timer
from .casuale import Casuale

__all__ = ["Vettore2D", "Timer", "Casuale"]

toolkit_gioco/vettore.py

"""Vettore 2D con operazioni comuni."""
from math import hypot, cos, sin, radians, degrees, atan2
from typing import Tuple

class Vettore2D:
    def __init__(self, x: float = 0, y: float = 0):
        self.x = x
        self.y = y
    
    def __add__(self, other: "Vettore2D") -> "Vettore2D":
        return Vettore2D(self.x + other.x, self.y + other.y)
    
    def __mul__(self, scalare: float) -> "Vettore2D":
        return Vettore2D(self.x * scalare, self.y * scalare)
    
    def lunghezza(self) -> float:
        return hypot(self.x, self.y)
    
    def normalizzato(self) -> "Vettore2D":
        l = self.lunghezza()
        return Vettore2D(self.x / l, self.y / l) if l > 0 else Vettore2D(0, 0)
    
    def angolo(self) -> float:
        return degrees(atan2(self.y, self.x))
    
    @classmethod
    def da_angolo(cls, angolo_gradi: float, lunghezza: float = 1) -> "Vettore2D":
        rad = radians(angolo_gradi)
        return cls(cos(rad) * lunghezza, sin(rad) * lunghezza)
    
    def __repr__(self):
        return f"Vettore2D({self.x:.2f}, {self.y:.2f})"

toolkit_gioco/timer.py

"""Timer per cooldown, durate, FPS."""
import time

class Timer:
    def __init__(self, durata: float):
        self.durata = durata
        self.inizio = 0
        self.attivo = False
    
    def avvia(self):
        self.inizio = time.perf_counter()
        self.attivo = True
    
    def pronto(self) -> bool:
        if not self.attivo:
            return False
        if time.perf_counter() - self.inizio >= self.durata:
            self.attivo = False
            return True
        return False
    
    def reset(self):
        self.attivo = False
    
    @property
    def rimanente(self) -> float:
        if not self.attivo:
            return 0
        return max(0, self.durata - (time.perf_counter() - self.inizio))

toolkit_gioco/casuale.py

"""Wrapper random con seed e utility gioco."""
import random
from typing import List, TypeVar, Sequence

T = TypeVar('T')

class Casuale:
    def __init__(self, seed: int = None):
        self.rng = random.Random(seed)
    
    def intero(self, a: int, b: int) -> int:
        return self.rng.randint(a, b)
    
    def float(self, a: float = 0, b: float = 1) -> float:
        return self.rng.uniform(a, b)
    
    def scelta(self, seq: Sequence[T]) -> T:
        return self.rng.choice(seq)
    
    def scelte(self, seq: Sequence[T], k: int) -> List[T]:
        return self.rng.choices(seq, k=k)
    
    def campione(self, seq: Sequence[T], k: int) -> List[T]:
        return self.rng.sample(seq, k)
    
    def mescola(self, lst: List[T]) -> None:
        self.rng.shuffle(lst)
    
    def probabilita(self, p: float) -> bool:
        """True con probabilità p (0.0-1.0)."""
        return self.rng.random() < p

demo_toolkit.py

"""Demo toolkit gioco."""
from toolkit_gioco import Vettore2D, Timer, Casuale
import time

rng = Casuale(42)  # Seed fisso per demo riproducibile

# Vettore
player = Vettore2D(100, 100)
direzione = Vettore2D.da_angolo(45, 10)
player = player + direzione
print(f"Player si muove a: {player}")

# Timer cooldown
cooldown = Timer(1.0)  # 1 secondo
cooldown.avvia()
print("Attacco! Cooldown avviato...")
while not cooldown.pronto():
    time.sleep(0.2)
    print(f"  Rimanente: {cooldown.rimanente:.1f}s")
print("Pronto per nuovo attacco!")

# Casuale
print(f"Dado: {rng.intero(1, 6)}")
print(f"Critico (20%): {rng.probabilita(0.2)}")
loot = ["spada", "scudo", "pozione", "oro"]
print(f"Loot: {rng.scelta(loot)}")

9. Tabella riassuntiva: import cheat sheet

| Sintassi | Quando usare | Esempio | | ---------- | -------------- | --------- | | import modulo | Default, namespace pulito | import math | | from modulo import nome | Usi 1-2 cose spesso | from math import pi, sin | | import modulo as alias | Nome lungo / conflitto | import random as rnd | | from . import modulo | Import relativo (stesso package) | from . import vettore | | from .. import modulo | Import relativo (package padre) | from ..core import motore |


10. Esercizi pratici

  1. Modulo dadi.py: Funzioni d6(), d20(), roll(ndm) es. roll("3d6") → somma 3 dadi 6 facce
  2. Modulo colori.py: Costanti ROSSO = (255,0,0), funzioni mescola_colori(c1, c2), scala_grigi(colore)
  3. Package utilita: Crea cartella con stringhe.py, liste.py, file.py, __init__.py che esporta tutto
  4. Virtual env: Crea venv, installa pygame, scrivi script che importa e stampa pygame.version.ver
  5. Refactoring: Sposta funzioni matematiche Cap. 4 in matematica.py, importale in calcolatrice.py

11. Checklist fine capitolo

  • [ ] Usi import, from ... import, import ... as
  • [ ] Conosci random: randint, choice, shuffle, seed
  • [ ] Usi time: sleep, perf_counter, strftime
  • [ ] Usi math: sqrt, sin/cos, hypot, radians/degrees
  • [ ] Crea moduli .py propri e li importi
  • [ ] Capisci if __name__ == "__main__":
  • [ ] Sai creare package con __init__.py
  • [ ] Usi pip install e requirements.txt

Prossimo capitolo

Capitolo 7: Pygame e i primi giochi — Finestra, loop eventi, disegna forme, input tastiera/mouse. La libreria standard per giochi 2D in Python.

👉 Leggi il Capitolo 7 →


Serie "Divento Programmatore: Python e i Giochi" (Cervello Elettronico Vol.2). Codice completo, tabelle, esercizi. Target 10-14 anni + guide adulti.

Per approfondire

Fonti e riferimenti

Condividi LinkedIn Facebook X WhatsApp
Continua a leggere

Tutti gli articoli del blog

Strumenti gratuiti