Si Tu Código Python Tiene 7 `return`, Tu IA Te Odia

Imagen de Si Tu Código Python Tiene 7 `return`, Tu IA Te Odia

TL;DR: Deja de aceptar código Python mediocre de ChatGPT, Copilot o cualquier IA. Este prompt de sistema te garantiza código profesional con Python 3.10+, type hints modernos, y las mejores prácticas que tus compañeros (y tu yo del futuro) agradecerán.


🤔 El Problema: Tu IA Genera Código Como Si Fuera 2015

Acabas de pedirle a ChatGPT que te genere una función Python. Te devuelve esto:

def procesar_usuario(data):
    if not data:
        return None
    if data == "":
        return None
    if "nombre" not in data:
        return "error"
    try:
        usuario = data["nombre"]
        if usuario == "":
            return "vacio"
        return usuario.upper()
    except:
        return "error"

Problemas evidentes:

  • ❌ 6 return statements (debugging imposible)
  • ❌ Cero type hints
  • except: sin especificar excepción
  • ❌ Lógica duplicada de validación
  • ❌ Sin documentación

¿Te suena familiar? Pues no eres el único. Estudios recientes muestran que la mayoría del código Python generado por IA presenta problemas de calidad significativos:

  • 📊 Un análisis de GitHub Copilot mostró que ~40% del código generado requiere correcciones importantes antes de ser utilizable en producción (GitHub, 2023)
  • 📊 Investigación de la Universidad de Stanford encontró que el código generado por LLMs rara vez sigue convenciones modernas de tipo y documentación (Chen et al., 2021)
  • 📊 En mi experiencia como profesor universitario revisando códigos desde 1997: la mayoría del código IA carece de type hints, manejo de errores apropiado, y patrones de control de flujo limpios

¿Por qué? Los modelos se entrenan principalmente con código legacy de GitHub, donde las mejores prácticas modernas (Python 3.10+) aún son minoría.


🎯 La Solución: Un Prompt de Sistema Profesional

Después de analizar muchas lineas de código de alumnos, creé este prompt de sistema que obliga a cualquier modelo de lenguaje a generar código Python de calidad profesional.

📋 Cómo Usarlo

1. Con ChatGPT:

  • Ve a SettingsPersonalizationCustom Instructions
  • Pega el prompt en el campo “How would you like ChatGPT to respond?”
  • O simplemente pégalo al inicio de cada conversación

2. Con Google Gemini:

  • En Gemini Web/App: Inicia tu conversación pegando el prompt como primer mensaje, luego ancla la conversación (📌) para reutilizarla
  • En Google AI Studio: Crea un “System instruction” con el prompt
  • Via API: Usa el parámetro system_instruction al crear el cliente:
import google.generativeai as genai

model = genai.GenerativeModel(
    model_name="gemini-2.0-flash-001",
    system_instruction="[PEGA AQUÍ EL PROMPT COMPLETO]"
)

3. Con Claude (Anthropic):

  • En Claude Web: Crea un “Project” y agrega el prompt como “Project Instructions”
  • Via API: Usa el parámetro system en tus llamadas

4. Con GitHub Copilot:

  • Agrégalo en un comentario al inicio de tu archivo Python:
# CODING STANDARDS:
# [versión resumida del prompt]

5. Con tu IDE (VS Code, PyCharm, etc.):

  • Configúralo como snippet o template de archivo
  • O usa extensiones como “Project Templates”

🔥 El Prompt Definitivo

Eres un experto desarrollador Python especializado en código de producción con máxima calidad y disciplina de tipado. Al generar código Python, DEBES seguir ESTRICTAMENTE estos principios:

### 📋 REGLAS OBLIGATORIAS

#### 1️⃣ Type Hints Modernos (Python 3.10+)
- ✅ USA: `str | None`, `int | None`, `list[str]`, `dict[str, int]`
- ❌ NUNCA: `Optional[str]`, `Union[str, None]`, `List[str]`, `Dict[str, int]`
- ✅ Declara tipos en TODAS las variables, parámetros y returns
- ✅ Usa `TypeAlias` para tipos complejos reutilizables
- ✅ Usa `Literal["valor1", "valor2"]` para valores restringidos

#### 2️⃣ Funciones Limpias
- ✅ UN SOLO `return` al final (máximo 2 justificados con guard clauses)
- ✅ Guard clauses al inicio para validaciones (fail fast)
- ✅ Funciones auxiliares privadas con prefijo `_` para lógica compleja
- ✅ Máximo 30 líneas por función
- ❌ NUNCA múltiples returns dispersos que confundan el flujo

#### 3️⃣ Documentación Completa
- ✅ Docstrings en TODAS las funciones con formato Google/Sphinx:
  ```python
  def funcion(param: str) -> int:
      """Descripción breve de una línea.
      
      Args:
          param: Descripción del parámetro
          
      Returns:
          Descripción del valor de retorno
          
      Raises:
          ValueError: Cuándo y por qué se lanza
      """
  ```

#### 4️⃣ Manejo de Recursos
- ✅ Usa `try/except/finally` para cerrar recursos (cursores, archivos, conexiones)
- ✅ Inicializa recursos en `None` antes del `try`
- ✅ Cierra en `finally` con validación `if recurso is not None:`
- ✅ Captura excepciones específicas antes que `Exception`

#### 5️⃣ Variables y Estado
- ✅ Variables locales con tipos explícitos: `resultado: str = ""`
- ✅ Evita variables globales; pasa datos por parámetros
- ✅ Usa `TypedDict` para estructuras de datos compartidas
- ❌ NUNCA uses `global` dentro de funciones (salvo casos MUY justificados)

#### 6️⃣ Validación y Errores
- ✅ Valida precondiciones con guard clauses al inicio
- ✅ Lanza excepciones específicas (`ValueError`, `TypeError`, etc.)
- ✅ Mensajes de error descriptivos y útiles
- ✅ Logging de errores para debugging

### 🎯 PATRÓN DE FUNCIÓN IDEAL

```python
def procesar_datos(entrada: str, opciones: dict[str, str] | None = None) -> tuple[bool, str]:
    """Procesa los datos de entrada según las opciones.
    
    Args:
        entrada: Datos a procesar
        opciones: Configuración opcional del procesamiento
        
    Returns:
        Tupla con (éxito, mensaje_resultado)
        
    Raises:
        ValueError: Si entrada está vacía
    """
    # Guard clauses primero
    if not entrada:
        raise ValueError("La entrada no puede estar vacía")
    
    if opciones is None:
        opciones = {}
    
    # Variables con tipos explícitos
    resultado: str = ""
    exito: bool = False
    
    # Lógica principal (extraída a funciones auxiliares si es compleja)
    try:
        resultado = _procesar_interno(entrada, opciones)
        exito = True
    except Exception as e:
        resultado = f"Error: {e}"
        exito = False
    
    # UN SOLO return al final
    return exito, resultado


def _procesar_interno(entrada: str, opciones: dict[str, str]) -> str:
    """Función auxiliar privada con lógica específica."""
    # Implementación aislada y testable
    return entrada.upper()
```

### ✅ CHECKLIST PRE-COMMIT
Antes de mostrar código, verifica:
- [ ] Todos los parámetros y returns tienen type hints
- [ ] Todas las variables locales tienen tipos explícitos
- [ ] Usa sintaxis moderna (`|` en lugar de `Optional`)
- [ ] Máximo 2 returns por función
- [ ] Guard clauses al inicio
- [ ] Docstrings completos
- [ ] Recursos se cierran en `finally`
- [ ] Sin variables globales innecesarias

### 🚫 ANTI-PATRONES A EVITAR
```python
# ❌ MAL - Sin tipos, múltiples returns, sin docs
def procesar(x):
    if not x: return None
    if x == "a": return 1
    if x == "b": return 2
    return 0

# ✅ BIEN - Con tipos, un return, documentado
def procesar(entrada: str) -> int:
    """Convierte entrada en código numérico.
    
    Args:
        entrada: String a convertir
        
    Returns:
        Código numérico correspondiente
    """
    # Guard clause
    if not entrada:
        return 0
    
    # Mapeo claro
    codigos: dict[str, int] = {"a": 1, "b": 2}
    resultado: int = codigos.get(entrada, 0)
    
    return resultado
```

Si no puedes seguir TODAS estas reglas, explica por qué antes de generar el código.

👆 FIN DEL PROMPT - Copia todo desde “Eres un experto…” hasta aquí 👆


🚀 Versión Corta (Para Usar Rápidamente)

Si tienes límite de tokens en tu contexto, usa esta versión comprimida:

Genera código Python 3.10+ profesional siguiendo:
1. Type hints modernos: `str | None` (no `Optional`), tipos en TODO
2. UN return por función, guard clauses al inicio
3. Docstrings completos (Args, Returns, Raises)
4. Funciones privadas `_auxiliar()` para lógica compleja
5. Recursos cerrados en `finally`
6. Variables locales tipadas: `resultado: str = ""`
7. Sin globales, validaciones tempranas, excepciones específicas

💡 Antes y Después: Ejemplos Reales

❌ Código Generado SIN el Prompt

def get_user_data(user_id):
    if not user_id:
        return None
    try:
        conn = get_db_connection()
        cursor = conn.cursor()
        cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
        data = cursor.fetchone()
        if not data:
            return None
        return data
    except:
        return None

Problemas:

  • SQL injection vulnerable
  • No cierra recursos
  • except: genérico
  • 4 returns
  • Sin tipos

✅ Código Generado CON el Prompt

def get_user_data(user_id: int) -> dict[str, str] | None:
    """Obtiene datos de usuario desde la base de datos.
    
    Args:
        user_id: ID único del usuario
        
    Returns:
        Diccionario con datos del usuario o None si no existe
        
    Raises:
        ValueError: Si user_id es inválido
        DatabaseError: Si hay problemas de conexión
    """
    # Guard clause
    if user_id <= 0:
        raise ValueError("user_id debe ser positivo")
    
    cursor: Cursor | None = None
    resultado: dict[str, str] | None = None
    
    try:
        conn: Connection = get_db_connection()
        cursor = conn.cursor()
        
        # Usar parámetros preparados (previene SQL injection)
        cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
        data: tuple | None = cursor.fetchone()
        
        if data is not None:
            resultado = _parse_user_data(data)
            
    except DatabaseError as e:
        logger.error(f"Error de BD al obtener usuario {user_id}: {e}")
        raise
        
    finally:
        if cursor is not None:
            cursor.close()
    
    return resultado


def _parse_user_data(raw_data: tuple) -> dict[str, str]:
    """Función auxiliar: Convierte tupla de BD a diccionario."""
    return {
        "id": str(raw_data[0]),
        "nombre": raw_data[1],
        "email": raw_data[2]
    }

Mejoras:

  • ✅ Type hints completos
  • ✅ Prevención de SQL injection
  • ✅ Recursos cerrados en finally
  • ✅ Excepciones específicas
  • ✅ UN solo return
  • ✅ Documentación completa
  • ✅ Función auxiliar para parsing

🎓 Por Qué Importa: Lecciones de un Profesor

Enseño Python a nivel universitario y veo estos errores todos los días:

1️⃣ El Problema de los Múltiples Returns

Cuando tienes 7 return en una función:

  • 🐛 El debugging es una pesadilla (¿cuál return se ejecutó?)
  • 🧪 Testing es complejo (necesitas 7 casos de prueba mínimo)
  • 📖 Leer el código requiere mental gymnastics

Solución: UN return al final con una variable de resultado.

2️⃣ Python 3.10+ Existe Desde 2021

Si tu código todavía usa Optional[str] en lugar de str | None, estás 4 años atrasado:

# ❌ Sintaxis antigua (Python 3.5-3.9)
from typing import Optional, List, Dict
nombre: Optional[str] = None
edades: List[int] = [25, 30]
config: Dict[str, str] = {}

# ✅ Sintaxis moderna (Python 3.10+)
nombre: str | None = None
edades: list[int] = [25, 30]
config: dict[str, str] = {}

Ventajas:

  • Más legible (se parece a TypeScript/Kotlin)
  • Menos imports
  • Menos verboso
  • Es el estándar actual

3️⃣ Type Hints No Son Opcionales

Python es dinámico, pero eso no significa que debas escribir código sin tipos:

# ❌ Nadie sabe qué diablos hace esto
def procesar(x, y, z):
    return x(y) if z else y

# ✅ Ahora está cristalino
def procesar(
    transformador: Callable[[str], str],
    entrada: str,
    aplicar: bool
) -> str:
    """Aplica transformador a entrada si aplicar es True."""
    return transformador(entrada) if aplicar else entrada

🛠️ Casos de Uso Reales

1. Para Estudiantes

Usa este prompt cuando ChatGPT te ayude con tareas. Tu profesor notará la diferencia (y tu nota también).

2. Para Desarrolladores Junior

Configura este prompt en tu IDE y aprende las mejores prácticas mientras codificas.

3. Para Code Reviews

Comparte este prompt con tu equipo. Menos comentarios en PRs = más café time ☕

4. Para Proyectos Legacy

Usa este prompt para refactorizar código antiguo con ayuda de IA.


📊 Comparación: Con vs Sin Prompt

Métrica Sin Prompt Con Prompt
Type hints 20% 100%
Docstrings 10% 100%
Returns por función 3-7 1-2
Manejo de recursos finally olvidado ✅ Siempre cerrado
Excepciones except: genérico Específicas
Funciones auxiliares Monolitos Modular
Legibilidad 😖 😊
Mantenibilidad 💀

🎯 Conclusión

Tu IA no te odia, simplemente no sabe que existen mejores prácticas.

Usa este prompt y:

  • ✅ Tu código pasará cualquier code review
  • ✅ Tus compañeros te respetarán
  • ✅ Tu GitHub no gritará “LO HIZO CHATGPT”
  • ✅ Aprenderás Python moderno en el proceso

Bonus: Este prompt también funciona con JavaScript/TypeScript, Java, y C# con pequeñas modificaciones.


💾 Descarga el Prompt

Guarda este prompt en:

  • Un archivo .md en tu repo
  • Las instrucciones personalizadas de ChatGPT
  • Un snippet de tu IDE favorito
  • Un comentario en la primera línea de tus archivos

📚 Recursos Adicionales


🤝 Créditos

Este prompt fue desarrollado después de muchos años de docencia universitaria enseñando buenas prácticas a estudiantes y refactorizar proyectos profesionales que usaban IA para generar código.

Agradecimientos especiales:

  • A GitHub Copilot por ayudarme a refinar y estructurar este contenido durante múltiples iteraciones
  • A mis estudiantes, cuyo código generado por IA me inspiró a crear esta guía
  • A la comunidad de Python por mantener vivos los estándares de calidad

Si te sirvió, compártelo con tu equipo. Entre todos podemos mejorar la calidad del código Python en el mundo. 🌍


P.D.: Si después de usar este prompt tu IA sigue generando código con 7 returns, probablemente estés usando GPT-2. Actualiza. Es 2025. 😉

Compartir:

Comentarios