4. Convenciones de estilo en Python: PEP 8 aplicado con ejemplos

4.1 Objetivo del tema

PEP 8 es la guía de estilo más conocida para escribir código Python. No convierte automáticamente un mal diseño en buen diseño, pero ayuda a que el código tenga una forma consistente, predecible y fácil de leer.

En este tema aplicaremos convenciones de estilo sobre ejemplos concretos. Veremos nombres, indentación, longitud de línea, espacios, imports, constantes y organización básica del archivo.

Objetivo práctico: reconocer problemas de estilo en código Python y corregirlos sin cambiar el comportamiento del programa.

4.2 Por qué importa el estilo

Cuando cada archivo usa un criterio distinto, el lector pierde tiempo adaptándose. Un archivo usa nombres largos, otro usa abreviaturas, otro mezcla espacios de forma irregular y otro agrupa imports sin orden. Todo eso no siempre rompe el programa, pero aumenta la fricción para mantenerlo.

Las convenciones de estilo reducen decisiones pequeñas. Si el equipo ya sabe cómo nombrar funciones, dónde ubicar imports y cómo separar bloques, puede concentrarse en el problema real.

El estilo no reemplaza el diseño. Primero ayuda a que el código sea legible; luego permite detectar problemas de diseño con menos ruido.

4.3 Nombres en snake_case

En Python, las funciones y variables se escriben normalmente en snake_case. Esto significa usar minúsculas y separar palabras con guiones bajos.

Ejemplo poco recomendable:

def CalcularTotalVenta(Productos, TipoCliente):
    TotalFinal = 0
    return TotalFinal

Versión más alineada con PEP 8:

def calcular_total_venta(productos, tipo_cliente):
    total_final = 0
    return total_final

La convención no es un detalle menor: permite reconocer rápidamente si estamos viendo una función, una variable, una clase o una constante.

4.4 Clases en PascalCase

Los nombres de clases se escriben normalmente en PascalCase, es decir, cada palabra empieza con mayúscula y no se usan guiones bajos entre palabras.

class CalculadoraDeVentas:
    pass

Evita nombres como estos para clases:

class calculadora_de_ventas:
    pass


class calculadoraDeVentas:
    pass

Más adelante veremos diseño de clases. Por ahora nos interesa reconocer la convención visual.

4.5 Constantes en mayúsculas

Las constantes se escriben en mayúsculas con guiones bajos. En Python no son inmutables por obligación del lenguaje, pero la convención indica que no deberían cambiar durante la ejecución.

DESCUENTO_VIP = 0.15
IMPUESTO_ARGENTINA = 0.21
LIMITE_ENVIO_GRATIS = 10000

Esto es más expresivo que dejar números sueltos dentro de la función:

total = total - total * 0.15
total = total + total * 0.21

4.6 Indentación con cuatro espacios

Python usa la indentación como parte de la estructura del programa. PEP 8 recomienda cuatro espacios por nivel de indentación.

Ejemplo correcto:

def obtener_productos_validos(productos):
    productos_validos = []
    for producto in productos:
        if producto["cantidad"] > 0:
            productos_validos.append(producto)
    return productos_validos

No mezcles tabs y espacios. Aunque a veces el editor lo disimule, puede generar errores o diferencias visuales difíciles de detectar.

4.7 Espacios alrededor de operadores

Los espacios ayudan a leer expresiones. PEP 8 recomienda usar espacios alrededor de operadores como =, +, -, *, /, == y <.

Ejemplo difícil de leer:

total=precio*cantidad
if total<10000:
    total=total+1500

Versión más clara:

total = precio * cantidad
if total < 10000:
    total = total + 1500

También podemos usar operadores aumentados cuando mejoran la lectura:

total += 1500

4.8 Espacios después de comas

En listas, diccionarios, tuplas y argumentos de funciones se deja un espacio después de cada coma.

Ejemplo poco legible:

productos = [{"precio":3000,"cantidad":2},{"precio":1500,"cantidad":1}]

Versión más clara:

productos = [
    {"precio": 3000, "cantidad": 2},
    {"precio": 1500, "cantidad": 1},
]

Cuando una estructura de datos crece, distribuirla en varias líneas puede mejorar mucho la lectura.

4.9 Longitud de línea

PEP 8 sugiere limitar la longitud de línea para que el código pueda leerse sin desplazamiento horizontal. En muchos proyectos modernos se usa un límite cercano a 88, especialmente cuando se trabaja con Black, pero el criterio importante es evitar líneas demasiado largas.

Ejemplo difícil de revisar:

total = calcular_total_venta(productos, cliente, pais, aplicar_descuento=True, incluir_impuestos=True, incluir_envio=True)

Versión más cómoda:

total = calcular_total_venta(
    productos,
    cliente,
    pais,
    aplicar_descuento=True,
    incluir_impuestos=True,
    incluir_envio=True,
)

4.10 Imports al comienzo del archivo

Los imports se ubican al comienzo del archivo, antes de constantes, funciones y clases. Además, suelen agruparse en este orden:

  • Imports de la biblioteca estándar.
  • Imports de paquetes externos.
  • Imports del propio proyecto.

Ejemplo:

from datetime import date
from decimal import Decimal

import requests

from ventas import calcular_total_venta

En el próximo tema veremos herramientas que pueden ordenar imports automáticamente.

4.11 Evitar imports con asterisco

Los imports con * hacen menos claro de dónde viene cada nombre. En código de producción conviene evitarlos.

Evita esto:

from math import *

Prefiere importar lo que usas:

from math import ceil, floor

O importa el módulo completo si mejora la claridad:

import math

redondeado = math.ceil(importe)

4.12 Líneas en blanco

Las líneas en blanco separan ideas. PEP 8 recomienda dejar dos líneas en blanco entre funciones o clases de nivel superior, y una línea en blanco entre métodos dentro de una clase.

def calcular_subtotal(productos):
    return sum(
        producto["precio"] * producto["cantidad"]
        for producto in productos
    )


def aplicar_descuento(total, descuento):
    return total * (1 - descuento)

No conviene abusar de líneas en blanco dentro de una misma función. Úsalas para separar etapas reales del cálculo.

4.13 Comentarios útiles

Un comentario debe explicar algo que el código no comunica bien por sí mismo: una decisión, una restricción externa, una regla de negocio especial. No debe repetir mecánicamente lo que ya se lee.

Comentario innecesario:

# Suma el costo de envío al total.
total += COSTO_ENVIO

Comentario más útil:

# El envío se cobra antes de emitir la factura porque lo exige el sistema contable.
total += COSTO_ENVIO

Si necesitas muchos comentarios para explicar una función, tal vez la función necesita nombres mejores o una división en partes más pequeñas.

4.14 Aplicar estilo a ventas.py

Tomando el archivo mejorado en el tema anterior, revisa que cumpla estas reglas básicas:

  • Constantes en mayúsculas al comienzo del archivo.
  • Dos líneas en blanco antes de la función principal.
  • Función y variables en snake_case.
  • Cuatro espacios por nivel de indentación.
  • Espacios alrededor de operadores.
  • Líneas suficientemente cortas para leerse con comodidad.

Una versión ordenada de src/ventas.py puede ser:

DESCUENTO_VIP = 0.15
DESCUENTO_REGULAR = 0.05
IMPUESTO_ARGENTINA = 0.21
IMPUESTO_URUGUAY = 0.22
IMPUESTO_OTRO_PAIS = 0.19
LIMITE_ENVIO_GRATIS = 10000
COSTO_ENVIO = 1500


def calcular_total_venta(productos, cliente, pais):
    subtotal = 0
    for producto in productos:
        if producto["cantidad"] > 0:
            subtotal += producto["precio"] * producto["cantidad"]

    total_con_descuento = subtotal
    if cliente == "vip":
        total_con_descuento -= subtotal * DESCUENTO_VIP
    elif cliente == "regular":
        total_con_descuento -= subtotal * DESCUENTO_REGULAR

    total_con_impuesto = total_con_descuento
    if pais == "AR":
        total_con_impuesto += total_con_descuento * IMPUESTO_ARGENTINA
    elif pais == "UY":
        total_con_impuesto += total_con_descuento * IMPUESTO_URUGUAY
    else:
        total_con_impuesto += total_con_descuento * IMPUESTO_OTRO_PAIS

    total_final = total_con_impuesto
    if total_final < LIMITE_ENVIO_GRATIS:
        total_final += COSTO_ENVIO

    return round(total_final, 2)

4.15 Verificar que el comportamiento no cambió

Después de aplicar cambios de estilo, ejecuta las pruebas:

python -m pytest

Si las pruebas fallan, revisa el cambio. Un ajuste de estilo no debería modificar cálculos, condiciones ni datos de entrada.

Un cambio de estilo debería ser fácil de revisar: la intención es ordenar la forma del código, no alterar las reglas de negocio.

4.16 Ejercicio guiado

Corrige el estilo de este código sin cambiar su comportamiento:

IVA=0.21
def Calc(precio,cant,cliente):
  total=precio*cant
  if cliente=="vip":total=total-total*0.15
  total=total+total*IVA
  return round(total,2)

Una posible versión corregida es:

IVA = 0.21
DESCUENTO_VIP = 0.15


def calcular_total(precio, cantidad, cliente):
    total = precio * cantidad
    if cliente == "vip":
        total -= total * DESCUENTO_VIP

    total += total * IVA
    return round(total, 2)

4.17 Ejercicio propuesto

Mejora el estilo del siguiente fragmento. No cambies el resultado esperado.

def obtener(us):
 a=[]
 for x in us:
  if x["activo"]==True and x["email"]!="":
   a.append(x["email"])
 return a

Aplica estas mejoras:

  • Usa indentación de cuatro espacios.
  • Cambia nombres poco claros.
  • Agrega espacios alrededor de operadores.
  • Evita comparar booleanos con == True.
  • Conserva el mismo comportamiento.

4.18 Lista de verificación

Antes de continuar, verifica que puedes aplicar estas convenciones:

  • Funciones y variables en snake_case.
  • Clases en PascalCase.
  • Constantes en mayúsculas.
  • Cuatro espacios por nivel de indentación.
  • Imports ordenados al comienzo del archivo.
  • Espacios consistentes en expresiones y argumentos.
  • Líneas suficientemente cortas.
  • Comentarios útiles y no redundantes.

4.19 Conclusión

En este tema aplicamos convenciones de estilo de Python con ejemplos concretos. Vimos que PEP 8 ayuda a mantener una forma uniforme del código, reduce ruido visual y facilita la revisión.

En el próximo tema usaremos herramientas para automatizar parte de este trabajo: Black para formatear e isort para ordenar imports. Así podremos concentrarnos más en decisiones de diseño y menos en discusiones manuales de formato.