PEP 8: Guía de Estilo Python para Código Profesional

👤 Admin 📅 20 de octubre, 2025 ⏱ 16 min 🏷 Python Avanzado

¿Qué es PEP 8?

PEP 8 es la guía de estilo oficial para código Python. Define convenciones sobre cómo formatear código para hacerlo más legible y consistente. Seguir PEP 8 es fundamental para escribir código profesional que otros desarrolladores puedan entender fácilmente.

¿Por Qué es Importante?

  • Legibilidad: Código más fácil de leer y entender
  • Mantenimiento: Facilita actualizaciones y correcciones
  • Colaboración: Estándar común en equipos
  • Profesionalismo: Demuestra conocimiento de mejores prácticas
  • Comunidad: Código consistente con proyectos open source

Indentación

Regla Principal: 4 Espacios

# Correcto
def mi_funcion():
    if True:
        print("Hola")

# Incorrecto - 2 espacios
def mi_funcion():
  if True:
    print("Hola")

# Incorrecto - tabs
def mi_funcion():
	if True:
		print("Hola")

Continuación de Línea

# Correcto - alineado con delimitador de apertura
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

# Correcto - indentación extra para distinguir
def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

# Correcto - hanging indent
foo = long_function_name(
    var_one, var_two,
    var_three, var_four)

# Incorrecto - argumentos en primera línea sin indentación
foo = long_function_name(var_one, var_two,
    var_three, var_four)

Longitud de Línea

Máximo 79 Caracteres

# Correcto - menos de 79 caracteres
def mi_funcion(parametro1, parametro2):
    return parametro1 + parametro2

# Correcto - dividir líneas largas
resultado = mi_funcion_con_nombre_largo(
    parametro_uno,
    parametro_dos,
    parametro_tres
)

# Correcto - usar paréntesis para dividir
texto = (
    "Esta es una línea muy larga que necesita "
    "ser dividida en múltiples líneas para "
    "mantener la legibilidad del código"
)

Líneas en Blanco

# Dos líneas en blanco antes de definiciones de clase
class MiClase:
    pass


class OtraClase:
    pass


# Dos líneas en blanco antes de funciones de nivel superior
def funcion_principal():
    pass


def otra_funcion():
    pass


# Una línea en blanco entre métodos
class MiClase:
    def metodo_uno(self):
        pass
    
    def metodo_dos(self):
        pass

Imports

Orden de Imports

# 1. Biblioteca estándar
import os
import sys
from datetime import datetime

# 2. Bibliotecas de terceros
import requests
import pandas as pd
from flask import Flask

# 3. Imports locales
from mi_modulo import mi_funcion
from .otro_modulo import OtraClase

Formato de Imports

# Correcto - imports en líneas separadas
import os
import sys

# Correcto - múltiples items de un módulo
from subprocess import Popen, PIPE

# Incorrecto
import os, sys

# Correcto - imports absolutos preferidos
from mipaquete.subpaquete import modulo

# Aceptable - imports relativos explícitos
from . import modulo_hermano
from ..paquete_padre import otro_modulo

Espacios en Blanco

Evitar Espacios Innecesarios

# Correcto
spam(ham[1], {eggs: 2})

# Incorrecto
spam( ham[ 1 ], { eggs: 2 } )

# Correcto
foo = (0,)

# Incorrecto
bar = (0, )

# Correcto
if x == 4:
    print(x, y)
    x, y = y, x

# Incorrecto
if x == 4 :
    print(x , y)
    x , y = y , x

Operadores

# Correcto - un espacio alrededor de operadores
x = 1
y = 2
resultado = x + y

# Correcto - sin espacios en prioridad alta
i = i + 1
submitted += 1
x = x*2 - 1
hypot2 = x*x + y*y
c = (a+b) * (a-b)

# Correcto - asignación en argumentos
def complex(real, imag=0.0):
    return magic(r=real, i=imag)

# Incorrecto
x=1
y=2
resultado=x+y

Convenciones de Nombres

Variables y Funciones - snake_case

# Correcto
mi_variable = 10
nombre_completo = "Ana García"

def calcular_promedio(numeros):
    return sum(numeros) / len(numeros)

# Incorrecto
miVariable = 10  # camelCase
NombreCompleto = "Ana"  # PascalCase

def CalcularPromedio(numeros):  # PascalCase
    pass

Clases - PascalCase

# Correcto
class MiClase:
    pass

class UsuarioAdministrador:
    pass

# Incorrecto
class mi_clase:  # snake_case
    pass

class usuarioAdministrador:  # camelCase
    pass

Constantes - UPPER_CASE

# Correcto
MAX_OVERFLOW = 100
TOTAL_ITEMS = 50
PI = 3.14159

# Incorrecto
max_overflow = 100
MaxOverflow = 100

Métodos y Variables Privadas - _prefijo

class MiClase:
    def __init__(self):
        self.publico = "visible"
        self._privado = "interno"  # Convención de privado
        self.__muy_privado = "name mangling"  # Name mangling
    
    def metodo_publico(self):
        return self._metodo_privado()
    
    def _metodo_privado(self):
        return "interno"

Comentarios

Comentarios de Línea

# Correcto - comentario sobre el código
x = x + 1  # Incrementar x

# Correcto - comentario de bloque
# Este es un comentario más largo que explica
# algo complejo que necesita múltiples líneas
# para ser completamente claro.
if x > 0:
    print("Positivo")

# Incorrecto - comentario obvio
x = x + 1  # sumar uno a x

Docstrings

def mi_funcion(parametro1, parametro2):
    """
    Breve descripción de la función.
    
    Descripción más detallada si es necesario.
    Puede tener múltiples párrafos.
    
    Args:
        parametro1 (int): Descripción del parámetro 1
        parametro2 (str): Descripción del parámetro 2
    
    Returns:
        bool: Descripción del valor de retorno
    
    Raises:
        ValueError: Cuándo se lanza esta excepción
    
    Examples:
        >>> mi_funcion(5, "test")
        True
    """
    return True


class MiClase:
    """
    Breve descripción de la clase.
    
    Descripción más detallada de qué hace la clase
    y cómo usarla.
    
    Attributes:
        atributo1 (int): Descripción del atributo
        atributo2 (str): Descripción del atributo
    """
    
    def __init__(self, valor):
        """Inicializar la clase con un valor."""
        self.valor = valor

Comparaciones

# Correcto - usar 'is' para None
if x is None:
    pass

# Incorrecto
if x == None:
    pass

# Correcto - comparar con True/False
if greeting:
    pass

# Incorrecto
if greeting == True:
    pass

# Correcto - verificar listas vacías
if not seq:
    pass

# Incorrecto
if len(seq) == 0:
    pass

Expresiones y Sentencias

Múltiples Sentencias

# Correcto
if foo == 'blah':
    do_blah_thing()
do_one()
do_two()

# Incorrecto - múltiples sentencias en una línea
if foo == 'blah': do_blah_thing()
do_one(); do_two()

Comprensiones

# Correcto - simple y legible
result = [x for x in range(10) if x % 2 == 0]

# Correcto - dividir si es muy largo
result = [
    x * 2
    for x in range(10)
    if x % 2 == 0
    if x > 5
]

# Incorrecto - demasiado complejo
result = [x if x > 0 else -x if x < -10 else 0 for x in range(-20, 20) if x != 0]

Ejemplo de Código Completo PEP 8

"""
Módulo de ejemplo siguiendo PEP 8.

Este módulo demuestra las convenciones de estilo
de Python según PEP 8.
"""

import os
import sys
from datetime import datetime

import requests
from flask import Flask


# Constantes
MAX_CONNECTIONS = 100
DEFAULT_TIMEOUT = 30


class UserManager:
    """
    Gestiona operaciones de usuarios.
    
    Esta clase proporciona métodos para crear, actualizar
    y eliminar usuarios del sistema.
    
    Attributes:
        users (list): Lista de usuarios activos
        max_users (int): Número máximo de usuarios permitidos
    """
    
    def __init__(self, max_users=100):
        """Inicializar el gestor de usuarios."""
        self.users = []
        self.max_users = max_users
        self._last_update = None
    
    def add_user(self, username, email):
        """
        Agregar un nuevo usuario.
        
        Args:
            username (str): Nombre de usuario único
            email (str): Dirección de email del usuario
        
        Returns:
            bool: True si se agregó exitosamente, False en caso contrario
        
        Raises:
            ValueError: Si el username ya existe
        """
        if self._user_exists(username):
            raise ValueError(f"Usuario {username} ya existe")
        
        if len(self.users) >= self.max_users:
            return False
        
        user = {
            'username': username,
            'email': email,
            'created_at': datetime.now()
        }
        self.users.append(user)
        self._last_update = datetime.now()
        return True
    
    def _user_exists(self, username):
        """Verificar si un usuario existe (método privado)."""
        return any(user['username'] == username for user in self.users)
    
    def get_user_count(self):
        """Obtener el número total de usuarios."""
        return len(self.users)


def calculate_average(numbers):
    """
    Calcular el promedio de una lista de números.
    
    Args:
        numbers (list): Lista de números
    
    Returns:
        float: Promedio de los números
    
    Raises:
        ValueError: Si la lista está vacía
    """
    if not numbers:
        raise ValueError("La lista no puede estar vacía")
    
    return sum(numbers) / len(numbers)


def main():
    """Función principal del programa."""
    # Crear gestor de usuarios
    manager = UserManager(max_users=50)
    
    # Agregar usuarios
    try:
        manager.add_user('ana', 'ana@email.com')
        manager.add_user('luis', 'luis@email.com')
        print(f"Total usuarios: {manager.get_user_count()}")
    except ValueError as e:
        print(f"Error: {e}")
    
    # Calcular promedio
    numbers = [10, 20, 30, 40, 50]
    average = calculate_average(numbers)
    print(f"Promedio: {average}")


if __name__ == '__main__':
    main()

Herramientas para Verificar PEP 8

pycodestyle (antes pep8)

# Instalar
pip install pycodestyle

# Verificar archivo
pycodestyle mi_script.py

# Ver estadísticas
pycodestyle --statistics mi_script.py

flake8

# Instalar
pip install flake8

# Verificar
flake8 mi_script.py

# Configurar en setup.cfg
[flake8]
max-line-length = 88
exclude = .git,__pycache__,venv

black - Auto-formateador

# Instalar
pip install black

# Formatear archivo
black mi_script.py

# Ver cambios sin aplicar
black --check mi_script.py

# Formatear todo el proyecto
black .

autopep8

# Instalar
pip install autopep8

# Formatear archivo
autopep8 --in-place --aggressive mi_script.py

Configuración en Editores

VS Code (settings.json)

{
    "python.linting.enabled": true,
    "python.linting.pylintEnabled": false,
    "python.linting.flake8Enabled": true,
    "python.formatting.provider": "black",
    "editor.formatOnSave": true,
    "editor.rulers": [79, 120]
}

PyCharm

Settings → Editor → Code Style → Python → Configurar según PEP 8

Excepciones a las Reglas

PEP 8 reconoce que a veces es necesario romper las reglas:

  • Cuando seguir la regla haría el código menos legible
  • Para ser consistente con código circundante
  • En código legacy que no sigue PEP 8
  • Cuando el código necesita ser compatible con versiones antiguas

Resumen de Convenciones

  • ✅ Indentación: 4 espacios
  • ✅ Línea máxima: 79 caracteres
  • ✅ Funciones/variables: snake_case
  • ✅ Clases: PascalCase
  • ✅ Constantes: UPPER_CASE
  • ✅ Privados: _prefijo
  • ✅ Imports: ordenados y agrupados
  • ✅ Docstrings: en funciones y clases
  • ✅ Espacios: alrededor de operadores
  • ✅ Comparaciones: usar 'is' para None

Conclusión

Seguir PEP 8 es esencial para escribir código Python profesional. Aunque puede parecer restrictivo al principio, estas convenciones mejoran significativamente la legibilidad y mantenibilidad del código. Usa herramientas automáticas como black o flake8 para facilitar el cumplimiento de estas reglas. Recuerda: el código se lee mucho más de lo que se escribe.