21 puntos por GN⁺ 2025-07-17 | 6 comentarios | Compartir por WhatsApp
  • Con la tendencia reciente del desarrollo con IA, comenzó a aprender y usar Python de forma seria, y ahora siente una gran satisfacción con su ecosistema
  • Python ha evolucionado hasta convertirse en un lenguaje mucho más rápido y moderno que antes, y percibe avances importantes como las mejoras de rendimiento mediante Cython
  • Ha incorporado activamente herramientas y bibliotecas modernas de desarrollo como uv, ruff, pytest y Pydantic en su flujo de trabajo para aumentar la productividad
  • También aplica estructuras de proyecto y automatización para reducir la brecha entre los entornos de producción y el desarrollo basado en notebooks de Jupyter/scripts
  • Usa GitHub Actions, Docker y otras herramientas para construir de forma eficiente CI/CD, pruebas y gestión de infraestructura

Resumen de I’m Switching to Python and Actually Liking It

Por qué se cambió a Python

  • En entornos de desarrollo centrados en IA, Python se ha consolidado como el lenguaje estándar de facto
  • Antes lo usaba solo para scripts simples, pero recientemente comenzó a usarlo seriamente para crear apps “listas para producción” como RAG, agentes e IA generativa
  • En ese proceso, notó que el ecosistema de Python ha evolucionado muchísimo en comparación con el pasado

Tres fortalezas de Python

  1. Ecosistema abundante de bibliotecas y herramientas: especializado en procesamiento de datos, análisis, web e IA
  2. Mejoras de rendimiento gracias a Cython y similares: permite optimización basada en compilación
  3. Legibilidad mejorada de la sintaxis: la sintaxis legacy como __init__ y __new__ queda más oculta, y se ofrece una sintaxis más intuitiva

Estructura del proyecto (basada en monorepo)

  • Prefiere una estructura monorepo que integra backend y frontend
    • Elige un único repositorio por eficiencia en la gestión del código, facilidad de búsqueda y simplificación del despliegue y de los pipelines de prueba
    • Considera que dividir en exceso un proyecto en varios repositorios es una señal de sobreingeniería
  • Un ejemplo típico de estructura del proyecto es el siguiente
    project/  
    ├── .github/ : workflows de CI/CD como GitHub Actions  
    ├── .vscode/ : configuración del entorno de VSCode  
    ├── docs/ : documentación estática y sitio basados en MkDocs  
    ├── project-api/ : backend con FastAPI e incluye datos/notebooks/herramientas/código fuente/pruebas  
    ├── project-ui/  : frontend en React/Next.js  
    ├── docker-compose.yml (ejecución integrada)  
    └── Makefile y otros scripts de automatización  
    
  • Separación de responsabilidades: el frontend obtiene mediante solicitudes HTTP los datos procesados por el servidor API
    • Se evita que el frontend haga procesamiento pesado de datos y se delegan las solicitudes HTTP a una API backend basada en Python
  • Cada directorio de módulos de Python se define claramente con __init__.py
  • Dentro de project-api, separa carpetas como src/app, notebooks, tools y tests

Herramientas y configuraciones principales

  • uv

    • Administrador de paquetes y herramienta de build moderna para Python ofrecida por Astral
    • Maneja rápidamente la mayoría de las tareas, como gestión de dependencias, creación de entornos virtuales e inicialización del proyecto
    • pyproject.toml es el archivo de configuración central, donde se integran todos los metadatos y dependencias
    • Se puede configurar rápidamente el entorno del proyecto con los comandos uv init, uv add y uv sync
  • ruff

    • Linter y formateador de código para Python ultrarrápido
    • Integra herramientas como isort, flake8 y autoflake
    • Permite hacer linting y corrección automática con ruff check y ruff format
    • Soporte nativo para la guía de estilo PEP 8
  • ty

    • Verificador estático de tipos para Python creado por Astral
    • Combinado con typing, es eficaz para el análisis estático y la prevención temprana de bugs
    • Aunque está en una etapa inicial de desarrollo, ya es lo bastante estable para usarse
  • pytest

    • Framework de pruebas de Python representativo para pruebas unitarias y entornos de pruebas extensibles
    • Permite integrar pruebas rápidamente con una convención simple de nombres de archivos y un solo comando
      • Se organizan en test_*.py y se ejecutan con uv run pytest
    • Sintaxis concisa y un ecosistema abundante de plugins
  • Pydantic

    • Biblioteca para validación de datos y gestión de configuración de entorno
    • Carga configuraciones basadas en variables de entorno .env y valida tipos
    • Permite gestionar de forma segura claves API, URL de bases de datos y más mediante la clase BaseSettings
  • MkDocs

    • Facilita la generación de sitios web estáticos y documentación para proyectos en Python
    • Permite aplicar rápidamente diseños atractivos al estilo de proyectos open source
    • También se integra fácilmente con GitHub Pages
  • FastAPI

    • Framework para construir APIs RESTful rápidas
    • Destaca por su validación y documentación automáticas, alto rendimiento e integración sencilla con Pydantic
    • Basado en Starlette y Pydantic, ofrece gran seguridad de tipos y buen rendimiento
  • Dataclasses

    • Funcionalidad estándar de Python para definir fácilmente clases centradas en datos
    • La generación automática de métodos especiales reduce mucho el código boilerplate

Control de versiones y automatización

  • GitHub Actions

    • Configura pipelines de CI separados para project-api y project-ui
    • Ofrece workflows optimizados para construir pipelines de CI en varios sistemas operativos
    • Con un entorno de pruebas basado en Docker, es posible probar en el mismo entorno que producción
  • Dependabot

    • Automatiza la actualización de dependencias y la gestión de parches de seguridad
  • Gitleaks

    • Herramienta para evitar fugas de información sensible (contraseñas, claves API, etc.) mediante revisiones de seguridad antes de los commits en git
  • Pre-commit Hooks

    • Herramienta para linting, formateo y revisiones de seguridad automáticas antes del commit
    • Se usa junto con ruff, gitleaks y otros para mantener la consistencia y la calidad del código

Automatización de infraestructura

  • Make

    • Brinda un flujo de trabajo de desarrollo consistente con comandos como make test y make infrastructure-up
    • Hay un Makefile tanto en la raíz del proyecto como en project-api
  • Docker & Docker Compose

    • project-api y project-ui se ejecutan por separado como contenedores
    • Toda la app puede levantarse con una sola línea: docker compose up --build -d
    • El Dockerfile incluye la instalación de uv y el comando para ejecutar la app de FastAPI

Cierre

  • Como se ve arriba, el entorno moderno de desarrollo en Python permite construir flujos de trabajo de producción eficientes y robustos
  • Es posible obtener muchos beneficios del crecimiento del ecosistema de Python y de la evolución de sus herramientas en áreas como IA, datos y desarrollo web
  • Se puede implementar una cultura de desarrollo integrada que abarque estructura monorepo, herramientas de automatización, linters y verificadores de tipos, entornos de prueba inmediatos, documentación y orquestación de infraestructura

6 comentarios

 
howudoin 2025-07-18

Python tiene una gran variedad de bibliotecas y frameworks, pero la desventaja es que la gestión de versiones de paquetes no está muy bien resuelta y los conflictos son frecuentes.
Se parece a Java de antes en la tendencia de sus ventajas y desventajas.

 
kylian 2025-07-18

El uv que también aparece en el artículo es realmente una joya. Además de ser rapidísimo, maneja muy bien las versiones y las dependencias, casi como npm, así que me estoy quedando con uv.

 
wyatt216 2025-07-18

Pero aun así, últimamente parece que con uv y poetry la gestión de versiones y los conflictos en su mayoría ya se han resuelto.

 
shakespeare 2025-07-18

¿También es adecuado para abarcar el ecosistema, incluso partes como React?

 
wyatt216 2025-07-18

Como el lenguaje es distinto, hay partes difíciles para integrarlo directamente con React, pero dependiendo de lo que quieran hacer, creo que también hay aspectos que sí serían posibles.
Personalmente, creo que el desarrollo frontend con Python es un área que todavía no está muy extendida.

 
GN⁺ 2025-07-17
Opiniones de Hacker News
  • En el código, mostrar un mensaje con OR como “Falta YOUTUBE_API_KEY o YOUTUBE_CHANNEL_ID” cuando falta una variable de entorno termina molestando al usuario en una situación donde ni siquiera hace falta usar OR. Es mucho mejor revisar cada valor por separado y decir con claridad cuál falta. La diferencia en tiempo de desarrollo es casi nula, así que recomendaría hacerlo así.

    • Es meterse mucho en un detalle pequeño, pero creo que este caso es ideal para usar el operador := (walrus). Por ejemplo, se puede usar directo así: if not (API_KEY := os.getenv("API_KEY")):. En lo personal, en herramientas internas dejo que os.environ["API_KEY"] lance KeyError sin atraparlo. Eso también me parece suficientemente claro.

    • Yendo más allá, me parece mucho mejor revisar las condiciones una por una y, si falta al menos una, mostrar todas de una vez. Así se evita la molestia de correr el programa por una variable faltante y luego encontrarse con otro error por otra variable distinta. A veces no queda otra que hacerlo más incómodo, pero si se puede, es mejor mostrar todo en una sola pasada.

    • Lo mejor es leer todas las variables de entorno y reportar de una vez cuáles faltan.

    • También se puede usar un flag booleano y hacer exit(1) una sola vez al final. Así puedes mostrar juntas todas las variables de entorno faltantes.

    • También se puede terminar con código 1 imprimiendo el mensaje directamente, como exit("Missing ...").

  • Si estás buscando una herramienta que genere automáticamente la estructura de un proyecto, recomiendo cookiecutter. Tengo varias plantillas que uso seguido, como python-lib, click-app, datasette-plugin y llm-plugin. Se usa así: uvx cookiecutter gh:simonw/python-lib

    • Hice algo llamado baker en Ruby. baker no copia el repo de plantillas, sino que genera una lista de tareas por hacer (una lista de pasos imperativos), y permite mezclar tareas manuales (como obtener y configurar una API key) con tareas automáticas (como uv init). Se puede usar sintaxis Markdown, interpolación de strings de Ruby y también bash. Lo hice porque ya estaba muy cansado de las configs basadas en yml.

    • Lo que está sonando últimamente es una herramienta llamada Copier. Para más detalles, revisa la documentación de Copier.

    • A mí más bien me gusta configurar proyectos nuevos. No siento necesidad de automatizar eso.

    • Creo que este tipo de herramientas de automatización de estructura encaja perfecto con los workflows de desarrollo con LLMs basados en agentes que están surgiendo ahora.

  • La idea de que “Python es más amigable para humanos porque viene preinstalado en la mayoría de Unix” me parece una lectura algo optimista. Apenas pasas de import json, entras muy rápido al infierno de virtualenv. Si quieres correr algo en Python 3.13.x sobre Ubuntu 22.04 o 24.04, Rocky 9, etc., al final venv, contenedores y gestores de versión se vuelven obligatorios.

    • Incluso una librería básica como import json, si el lenguaje no la incluyera, habría que instalarla aparte; en Python, la librería estándar da mucha productividad al inicio. Claro, en proyectos grandes no alcanza con la librería estándar, pero en la práctica he desplegado varios códigos reales usando solo eso, sin problemas de despliegue ni de gestión de seguridad. Además, manejar venv ya no es tan difícil como antes, y los package managers también han mejorado.

    • Una de mis teorías medio en broma es que la mitad de la razón por la que Docker/contenedores se expandieron tan rápido fue que ayudaron a superar el infierno de dependencias de Python. Mi primera experiencia con Python fue instalar un servicio en un servidor en 2012, y fue terrible: infierno de dependencias, comandos de venv, entornos difíciles de manejar, todo espantoso. También me la pasé sufriendo con pip, brew y entornos de macOS, y terminaba evitando Python apenas lo veía. Pero últimamente, gracias a uv, siento que Python mejoró bastante incluso para principiantes. Con uv init, uv add y uv run ya alcanza.

    • Creo que siempre hay que usar virtualenv. Al final no es más que un directorio, y ahora hasta salen advertencias si intentas instalar globalmente con pip, así que ya no es tan complicado como antes.

    • Es buena idea usar sí o sí virtualenv o contenedores. Aunque parezca más difícil de manejar, así evitas que actualizaciones o cambios de versión de librerías afecten todo el sistema.

    • Antes era común que el sistema trajera solo Python 2 por defecto, y a veces el propio sistema dependía de ese Python 2, así que en realidad era todavía más riesgoso.

  • Siento que Python es al mismo tiempo verboso e insuficiente. Para hacer algo simple, o terminas metiendo 500 dependencias, o para una tontería acabas escribiendo desde decenas hasta cientos de líneas. Por eso evito Python: hay demasiado trabajo innecesario. Prefiero Perl porque puedo terminar mucho más rápido y con más concisión. Python termina sintiéndose como programación por la programación, más que como una herramienta para hacer el trabajo.

    • Yo hago muchos proyectos sin dependencias. Con la librería estándar y un solo archivo se puede hacer muchísimo. Si tienes Python instalado, puedes bajarlo con curl y correrlo directo. Por ejemplo, tengo una herramienta CLI de manejo de dinero de 2000 líneas, plutus, que usa como 12 módulos estándar. Aproximadamente 25% del código es la parte de parsear comandos con argparse. Me gusta escribirlo de forma clara, con una línea por parámetro.

    • Dijiste que Perl es más rápido y más potente que Python; me da curiosidad qué ejemplos concretos tendrías.

    • En Python me resulta cómodo poder anidar estructuras de datos sin pensarlo demasiado. Puedes mezclar libremente listas, tuplas, diccionarios, etc., y acceder a todo con una sintaxis uniforme. Perl sin duda es más listo y más divertido, pero justo por eso a mí se me enreda más la cabeza. Python es más aburrido, pero tiene muchísima claridad y puedo volver a verlo cinco años después y entenderlo.

    • Creo que Python ya es bastante útil solo con la librería estándar.

  • A mí me gusta la estructura de monorepo, pero en una empresa donde trabajé antes eso terminó creando una estructura gigantesca y obesa que nadie quería tocar por miedo a romper código de otros equipos. El problema de fondo no era tanto el repo en sí, sino que se manejaba un solo requirements.txt para todo el repo o los scripts de build estaban enredados. En teoría, debería bastar con actualizar dependencias una vez para que todo el código quede seguro con los últimos parches, pero en la práctica nadie podía tocar eso. Los monorepos solo funcionan bien cuando la organización tiene una cultura muy NIH (como Google, con tendencia a construir todo por cuenta propia). Por experiencias así, empecé a valorar más una estructura de microservicios donde cada servicio coincide con la estructura de equipos de la organización. También vale la pena mirar Conway's law.

  • Python es el lenguaje que más se comporta como el pseudocódigo que escribo. Cada parte que en mi cabeza doy por obvia, Python también la resuelve con abstracciones intuitivas. Como vengo de una formación más matemática, eso me resultó muy satisfactorio. Claro que ahora también me gustan otros lenguajes, pero sigue teniendo encanto.

    • Para alguien que piensa de forma matemática, el lado OOP más bien dificulta el razonamiento. Importan la sustitución de equivalentes, mejores lambdas, evitar efectos secundarios, la inmutabilidad de los datos, etc. OOP es el paradigma que he conocido que se siente más alejado de las matemáticas.
  • Estoy armando proyectos casi siempre con exactamente el mismo patrón. Se parece tanto que hasta da miedo. Me pregunto si el ecosistema de desarrolladores Python no estará convergiendo cada vez más a un mismo estilo. Antes pensaba que mis elecciones eran originales, pero si todos terminamos haciendo lo mismo, me pregunto dónde quedó mi libre albedrío. Me recuerda al fenómeno de elegir nombres de bebé: creías que habías escogido algo único y en realidad era el nombre popular #2.

    • Esta estructura ya era popular en Python desde hace 10 años. Al final, parece que muchos ingenieros razonables llegan naturalmente al mismo patrón después de pensarlo bien.

    • Siento que el ego humano está extendido por todo el espectro como una onda piloto cuántica, y desde ahí se transforma en existencia. becoming-being, me hace reír.

  • Me da gusto ver que a más gente le está empezando a gustar Python. Yo originalmente prefería Ruby, pero por requerimientos de clientes terminé usándolo a la fuerza. Antes Ruby era mucho más lento, pero al obligarme a aprender Python me fui acostumbrando y ahora hasta lo disfruto. Sí tengo algunas diferencias de opinión sobre cómo usar Make: si no usas dependencias en absoluto, no es muy distinto de un script con un case... lo digo medio en broma, pero me da cierta nostalgia ver que la generación de ahora ya no está familiarizada con Make. Es un poco ese sentimiento de “en mis tiempos...”.

    • Ruby tiene una sintaxis mucho más bonita. Python, con eso de delimitar el scope solo por indentación, no es mi estilo.

    • Yo también empecé con un script lleno de case, pero al final evolucionó hacia un Makefile plano. Un Makefile es más estándar y más fácil de entender que un script cualquiera.

  • Me pregunto cuándo conviene usar Dataclass y cuándo Pydantic Basemodel. Si ya estás usando Pydantic, casi parece que podrías unificar todo con Pydantic, así que dudo si realmente hay una buena razón para seguir usando Dataclass.

    • El proyecto attrs tiene una comparación muy bien explicada. Está esta comparación oficial de attrs; claro, puede tener algo de sesgo, pero me parece que los argumentos lógicos son sólidos. También ayuda este blog.

    • Dataclass no soporta validación de objetos anidados. Por eso, para estructuras planas simples que solo sirven para pasar argumentos entre funciones, conviene más dataclass. Es más claro que recibir demasiados argumentos sueltos.

    • Hay un costo de rendimiento por la validación de datos al crear objetos. También hay alternativas mucho más ligeras y rápidas, como msgspec.

    • Si no necesitas validación ni serialización, Pydantic más bien es overhead innecesario. Mi regla es: si necesitas serialización, Pydantic; si no, dataclass.

    • Puedes usar directamente un dataclass existente con algo como TypeAdapter(MyDataclass), así que no veo por qué habría que crear además un modelo Pydantic aparte.

  • Últimamente, de hecho, me he mudado a otros lenguajes y estoy más satisfecho así. Resumí mis ideas sobre Python en este texto. Si más adelante me toca volver a usar Python, sí quiero probar cosas como uv, ruff y ty.

    • Yo también me pasé de Python a JS en backend y lo he disfrutado bastante. Coincido en que la instalación y gestión de paquetes de Python está rota. Pero para mí la mayor mejora de productividad fue async. Python tiene asyncio, pero hay varias formas en competencia y no se ha asentado un estándar claro. En JS todo converge a una sola forma, y eso me resultó mucho más cómodo. Incluso los detalles chicos, sumados, terminan haciendo una gran diferencia: en Python, el scope por indentación, los problemas de rutas relativas en imports, la sintaxis de objetos en JS, etc., se sienten más agradables. Ver también esta explicación relacionada.