Timeit en Python: medir el rendimiento correctamente

Publicado el: 11/07/2026
Tempo de leitura: 5 minutos
Medição de tempo de execução de código Python com timeit

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.py

La 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.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Dicas para otimizar scripts Python lentos
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Por qué tu script Python es lento y cómo mejorarlo

    Descubre por qué un script Python es lento y cómo mejorarlo con cProfile, timeit, estructuras correctas, generadores y mejores algoritmos.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026
    Leitura de variáveis de ambiente em projetos Python
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Variables de entorno en Python: guía segura

    Aprende a usar variables de entorno en Python, archivos .env, validación, conversión de tipos, secretos, pruebas y buenas prácticas.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Introdução ao uso de type hints em Python
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Type hints en Python: escribe código más claro

    Aprende type hints en Python con funciones, colecciones, Optional, TypedDict, Callable, genéricos, Protocol y herramientas de análisis.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Criação de cliente TCP simples usando Python
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Cliente TCP en Python con sockets: guía práctica

    Crea un cliente TCP en Python con sockets: conexión, bytes, framing, timeouts, errores, reintentos, protocolos, seguridad y código reutilizable.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Entendendo como o GIL afeta performance em Python
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    GIL de Python: qué es y cómo afecta al rendimiento

    Entiende el GIL de Python, su efecto en threads y CPU, y cuándo usar asyncio, multiprocessing, procesos o bibliotecas que

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026
    Configuração de logs em aplicações Python usando logging
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Logging en Python: guía completa para principiantes

    Aprende logging en Python: niveles, archivos, formatos, excepciones, handlers, rotación, loggers por módulo y buenas prácticas.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026