---
title: Si Tu Código Python Tiene 7 `return`, Tu IA Te Odia
date: '2025-10-19 10:00:00 +0200'
url: https://davidbuenov.com/2025/10/19/si-tu-codigo-python-tiene-7-return-tu-ia-te-odia.html
---

# 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:

```python
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](https://github.blog/2023-06-13-survey-reveals-ais-impact-on-the-developer-experience/))
- 📊 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](https://arxiv.org/abs/2107.03374))
- 📊 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 **Settings** → **Personalization** → **Custom 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:

```python
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:

```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

````markdown
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:

```markdown
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

```python
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

```python
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**:

```python
# ❌ 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:

```python
# ❌ 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

- [PEP 604: Union Type Syntax](https://peps.python.org/pep-0604/) - La razón detrás de `str | None`
- [PEP 586: Literal Types](https://peps.python.org/pep-0586/) - Para valores restringidos
- [Python Type Hints Cheat Sheet](https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html)

---

## 🤝 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. 😉
