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.
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__.
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.
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.
# 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
[ ] Differenze architetturali tra asyncio, threading e multiprocessing
[ ] Implementazione e casi d'uso delle metaclassi
PEP 8 - Style Guide for Python Code
Documentazione ufficiale Python (docs.python.org)