Python — Cheat Sheet

Tag: python, backend, scripting, oop, data-structures

Livello: intermedio

TL;DR: Riferimento rapido per concetti core, strutture dati e peculiarità di Python, utile per affrontare colloqui su backend e scripting.

Concetti chiave

Tipizzazione dinamica e forte: i tipi sono inferiti a runtime, ma non avvengono conversioni implicite tra tipi incompatibili.

Global Interpreter Lock (GIL): un mutex che protegge l'accesso agli oggetti Python, impedendo a thread multipli di eseguire bytecode contemporaneamente.

Gestione della memoria: basata su reference counting e un garbage collector generazionale per risolvere i cicli di riferimenti.

List Comprehension: sintassi concisa per creare liste basate su iterabili esistenti, generalmente più performante dei cicli for tradizionali.

Generatori: funzioni che usano yield per restituire un iteratore lazy, ottimizzando l'uso della memoria per sequenze molto grandi.

Decoratori: funzioni di ordine superiore che modificano il comportamento di altre funzioni o classi senza alterarne il codice sorgente.

Magic Methods (Dunder methods): metodi speciali come __init__, __str__, __eq__ che permettono di implementare comportamenti built-in e l'overloading degli operatori.

Duck Typing: se sembra un'anatra e starnazza come un'anatra, è un'anatra. Il controllo del tipo si basa sui metodi supportati, non sulla gerarchia delle classi.

Gestione del contesto: l'istruzione with garantisce la corretta acquisizione e rilascio delle risorse tramite il protocollo __enter__ e __exit__.

Domande tipiche e risposte pronte

Q: Qual è la differenza tra tuple e list?R: Le liste sono mutabili e usano parentesi quadre, le tuple sono immutabili e usano parentesi tonde. Uso le tuple per collezioni eterogenee o come chiavi di dizionari.

Q: Come aggiri il limite del GIL per operazioni CPU-bound?R: Utilizzo il modulo multiprocessing per creare processi separati invece di thread, poiché ogni processo ha il proprio interprete Python e il proprio GIL.

Q: Cosa fa l'istruzione yield?R: Trasforma una funzione in un generatore. Sospende l'esecuzione, restituisce un valore e mantiene lo stato locale per riprendere dal punto di interruzione alla chiamata successiva.

Insidie e errori comuni

Usare argomenti di default mutabili: definire def func(lista=[]) valuta la lista una sola volta, causando la condivisione dello stato tra le chiamate.

Modificare una lista mentre la si itera: provoca comportamenti imprevedibili. E' sempre meglio iterare su una copia o usare una list comprehension.

Fare confusione tra is (identità di memoria) e == (uguaglianza di valore).

Non chiudere i file esplicitamente: bisogna usare sempre il context manager with open(...) per evitare memory leak o file lock.

Snippet e comandi

# List comprehension con condizione
quadrati_pari = [x**2 for x in range(10) if x % 2 == 0]

# Decoratore base
def timer_decorator(func):
    def wrapper(*args, **kwargs):
        import time
        start = time.time()
        result = func(*args, **kwargs)
        print(f"Tempo di esecuzione: {time.time() - start}s")
        return result
    return wrapper

@timer_decorator
def operazione_pesante():
    pass

# Context manager personalizzato
class MioContextManager:
    def __enter__(self):
        print("Acquisisco risorsa")
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        print("Rilascio risorsa")

# Generatore infinito
def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

Da ripassare

[ ] Differenze architetturali tra asyncio, threading e multiprocessing

[ ] Implementazione e casi d'uso delle metaclassi

Riferimenti

PEP 8 - Style Guide for Python Code

Documentazione ufficiale Python (docs.python.org)

Jarvis Interviews
Jarvis