Una vez elegido el algoritmo correcto, quedan mejoras pequeñas para aprovechar CPU y memoria. No cambian el Big-O, pero reducen constantes y evitan trampas frecuentes.
Comparar enteros es directo; comparar objetos puede implicar evaluar varios atributos.
class Punto:
def __init__(self, x, y, activo):
self.x = x
self.y = y
self.activo = activo
def iguales(a, b):
return a.x == b.x and a.y == b.y and a.activo == b.activo
Si solo importa un campo para ordenar o filtrar, compara ese campo y evita reconstruir objetos completos.
Crear objetos en cada iteración agrega overhead y presiona al recolector de basura.
# Evitar: crear lista nueva en cada paso
for i in range(n):
tmp = [i]
usar(tmp)
# Mejor: reutilizar estructura cuando aplica
tmp = [0]
for i in range(n):
tmp[0] = i
usar(tmp)
Cuando es posible, reserva una vez fuera del loop o usa estructuras prealocadas.
Llamar funciones pequeñas agrega overhead de llamada y lookup en Python.
def cuadrado(x):
return x * x
def suma_cuadrados(valores):
total = 0
for x in valores:
total += x * x # en lugar de cuadrado(x) si es un hotspot
return total
En secciones críticas, mover el cálculo directo o usar funciones locales puede reducir el overhead.
Cualquier cálculo que no dependa del índice debe moverse fuera del ciclo.
def escala_vector(valores, factor):
k = 1.0 / factor # calculado una vez
for i in range(len(valores)):
valores[i] *= k
return k
Esto reduce operaciones repetidas y mejora la localidad de datos.
En Python no hay macros, pero conviene evitar evaluaciones repetidas.
def menor_de_tres(a, b, c):
return min(a, b, c)
Prefiere funciones built-in (como min, max, sum) que ya están optimizadas en C.
def suma_iterando(valores):
total = 0
for valor in valores:
total += valor
return total