El módulo timeit en Python permite medir pequeños fragmentos de código reduciendo parte del ruido que aparece al utilizar un reloj manual. Es útil para comparar dos implementaciones, comprobar una microoptimización o entender el coste de una operación repetida.
Timeit no sustituye un profiler ni una prueba completa de rendimiento. Sirve para preguntas concretas, como comparar una comprensión de lista con un bucle, evaluar dos estructuras de datos o medir una función pequeña en condiciones controladas.
Por qué no basta con time.time()
import time
start = time.time()
result = sum(range(1_000_000))
elapsed = time.time() - start
print(elapsed)Este método incluye ruido del sistema, resolución del reloj, calentamiento, tareas en segundo plano y una única ejecución. Además, una operación muy rápida puede medirse con poca precisión.
La documentación oficial de timeit explica cómo el módulo repite el código y utiliza un temporizador apropiado para la plataforma.
Primera medición con timeit()
import timeit
elapsed = timeit.timeit(
"sum(range(1000))",
number=10_000,
)
print(elapsed)number indica cuántas veces se ejecuta el fragmento. El resultado representa el tiempo total del lote, no el promedio por llamada.
average = elapsed / 10_000
print(average)Medir una función directamente
Evita strings cuando puedes pasar una función sin argumentos:
import timeit
def calculate():
return sum(
number * number
for number in range(1000)
)
elapsed = timeit.timeit(
calculate,
number=1000,
)
print(elapsed)La guía de funciones en Python explica cómo separar lógica y preparar unidades pequeñas que puedan medirse o probarse con facilidad.
Utilizar setup
import timeit
elapsed = timeit.timeit(
stmt="sorted(values)",
setup="values = list(range(1000, 0, -1))",
number=1000,
)
print(elapsed)El código de setup se ejecuta fuera del fragmento medido para cada lote. Esto evita incluir la creación de los datos cuando la pregunta se centra exclusivamente en el ordenamiento.
Decidir qué trabajo debe incluirse
A veces crear los datos forma parte del coste real. En ese caso debe quedar dentro de la función:
def complete_workflow():
values = list(range(1000, 0, -1))
return sorted(values)Define primero qué pregunta quieres responder. Medir solamente una parte puede producir una conclusión irrelevante para la aplicación real.
Comparar dos implementaciones
import timeit
def with_loop():
result = []
for number in range(1000):
result.append(number ** 2)
return result
def with_comprehension():
return [
number ** 2
for number in range(1000)
]
loop_time = timeit.timeit(
with_loop,
number=5000,
)
comprehension_time = timeit.timeit(
with_comprehension,
number=5000,
)
print("Bucle:", loop_time)
print("Comprensión:", comprehension_time)La guía de list comprehensions en Python explica cuándo una comprensión mejora la claridad y cuándo un bucle normal es preferible.
Utilizar repeat()
Una sola medición puede coincidir con una interrupción del sistema. repeat() ejecuta varios lotes:
import timeit
results = timeit.repeat(
"sum(range(1000))",
repeat=7,
number=10_000,
)
print(results)
print("Mejor:", min(results))Los valores mayores suelen incluir interferencias externas. El mejor resultado aproxima cuánto tarda la operación cuando el sistema no añade retrasos. También conviene observar la dispersión para detectar una prueba inestable.
Calcular el tiempo por operación
number = 10_000
results = timeit.repeat(
"sum(range(1000))",
repeat=5,
number=number,
)
best_per_call = min(results) / number
print(f"{best_per_call:.9f} segundos")Presentar el tiempo por llamada facilita comparar pruebas con cantidades de repeticiones diferentes.
Usar Timer para configuraciones reutilizables
from timeit import Timer
def transform(values):
return [value * 2 for value in values]
values = list(range(10_000))
timer = Timer(
stmt=lambda: transform(values)
)
print(
timer.repeat(repeat=5, number=1000)
)Timer resulta útil cuando quieres repetir la misma configuración o utilizar el método autorange().
Medir desde el terminal
python -m timeit "sum(range(1000))"Con preparación:
python -m timeit -s "values=list(range(1000))" "max(values)"La herramienta selecciona automáticamente una cantidad de bucles adecuada cuando no se especifica.
Comparar trabajos equivalentes
No compares una función que construye una lista completa con otra que solamente crea un generador sin consumirlo:
list_result = [
number * number
for number in range(1000)
]
generator = (
number * number
for number in range(1000)
)Para hacer un trabajo equivalente, consume el generador:
sum(
number * number
for number in range(1000)
)Preparar los datos fuera de la medición
import random
import timeit
values = [
random.randint(0, 1_000_000)
for _ in range(100_000)
]
value_set = set(values)
list_time = timeit.timeit(
lambda: 999_999 in values,
number=100,
)
set_time = timeit.timeit(
lambda: 999_999 in value_set,
number=100,
)
print(list_time, set_time)La creación del set queda fuera porque la pregunta compara búsquedas repetidas. Si solo realizaras una búsqueda, deberías incluir también el coste de construcción.
La guía de sets en Python explica por qué las pruebas de pertenencia suelen ser eficientes.
Microbenchmark frente a profiler
Timeit responde preguntas pequeñas. Para saber dónde una aplicación completa consume tiempo, utiliza un profiler:
python -m cProfile -s cumulative app.pyLa documentación oficial de los profilers de Python explica cProfile, profile y pstats. La guía interna de cProfile en Python muestra cómo identificar las funciones que realmente dominan el tiempo de ejecución.
Controlar el entorno
Para resultados comparables:
- utiliza la misma versión de Python;
- ejecuta en el mismo equipo y modo de energía;
- cierra tareas pesadas cuando sea posible;
- repite varios lotes;
- usa datos representativos;
- documenta parámetros y tamaños;
- evita mezclar red, disco o instalación con una microprueba de CPU.
Medir operaciones con archivos o red
Timeit no es ideal para servicios externos porque la latencia cambia y puede tener efectos secundarios. Para medir una función de alto nivel, utiliza observabilidad, percentiles y varias solicitudes controladas.
La guía sobre por qué un script de Python está lento presenta optimizaciones de algoritmos, estructuras de datos y bibliotecas.
Ejemplo: concatenación de strings
import timeit
def concatenate_with_plus(parts):
result = ""
for part in parts:
result += part
return result
def concatenate_with_join(parts):
return "".join(parts)
parts = ["python"] * 10_000
plus_time = timeit.timeit(
lambda: concatenate_with_plus(parts),
number=100,
)
join_time = timeit.timeit(
lambda: concatenate_with_join(parts),
number=100,
)
print(plus_time, join_time)Antes de generalizar la conclusión, prueba tamaños pequeños y grandes y comprueba que ambas funciones producen exactamente el mismo resultado.
Ejemplo: NumPy frente a Python puro
import timeit
import numpy as np
values = list(range(100_000))
array = np.arange(100_000)
python_time = timeit.timeit(
lambda: [value * 2 for value in values],
number=100,
)
numpy_time = timeit.timeit(
lambda: array * 2,
number=100,
)
print(python_time, numpy_time)La guía de NumPy y Pandas explica vectorización, arrays y procesamiento tabular.
Qué información guardar
Registra el código probado, versión de Python, plataforma, tamaño de entrada, número de repeticiones y mejor tiempo por llamada. Sin este contexto, un número aislado no permite reproducir ni interpretar la prueba.
Errores frecuentes
- Medir una sola ejecución.
- Comparar trabajos diferentes.
- Incluir preparación en una función y excluirla en otra.
- Optimizar una operación que no domina el tiempo total.
- Utilizar datos demasiado pequeños o irreales.
- Comparar equipos diferentes sin contexto.
- Medir red o disco como una microoperación estable.
- Elegir código menos legible por una diferencia insignificante.
Conclusión
Timeit es una herramienta precisa para comparar pequeños fragmentos en condiciones controladas. Define la pregunta, prepara datos de forma equivalente, utiliza repeat(), calcula el tiempo por operación y documenta el entorno. Para aplicaciones completas, encuentra primero el cuello de botella con un profiler y utiliza timeit solamente para evaluar alternativas concretas.






