Faragiri

Aprender Paquetes y entornos Python

Qué cambia en verdad un entorno virtual, por qué el import falla en una terminal y funciona en otra, y el archivo que hace la corrida reproducible.

5Secciones
4Minutos
4Profundidad

Cuatro capas, un import

Qué busca un import, y qué capa reemplaza la carpeta

Un entorno no agrega una capa, cambia las dos del medio, y por eso el mismo comando se comporta distinto en dos terminales.

  1. Su códigoSe importa primero, y por eso un archivo llamado random.py rompe todoel proyecto
  2. El site-packages del entornocertifi, charset_normalizer, idna, requests, urllib3, y nada máscambiado
  3. El intérprete del entornosys.prefix apunta aquí, y sys.base_prefix nocambiado
  4. El intérprete del sistema y sus paquetesSigue en la máquina, y a propósito fuera de la ruta de búsquedainvisible

Activar no cambia nada en esta pila. Edita el PATH para que escribir python llegue a la tercera capa, por lo que llamar al intérprete por su ruta completa funciona igual y nunca hay que recordarlo.

Pedir un paquete instala varios. Julián, que trabaja remoto desde Quito, midió esto el 2026-09-22 instalando requests en un entorno recién creado para un script que consulta el tipo de cambio: Successfully installed certifi-2026.7.22 charset_normalizer-3.5.1 idna-3.19 requests-2.34.2 urllib3-2.7.0, cinco paquetes por un solo nombre. Cuatro de ellos son decisión de otra persona, se van a actualizar según el calendario de esa persona, y ahora son suyos para mantener funcionando.

Cayeron dentro de la carpeta y en ningún otro lado. Desde el intérprete del entorno el import funciona; desde el intérprete del sistema en la misma terminal, import requests responde ModuleNotFoundError: No module named 'requests'. Ese es todo el mecanismo, y explica por qué el mismo comando le funciona a un colega y a uno no.

Qué es exactamente un entorno virtual

Es una carpeta con su propio intérprete y su propio site-packages, y un valor que lo delata: adentro, sys.prefix es distinto de sys.base_prefix. Esa comparación es la forma confiable de saber en qué entorno se está, y vale más que leer el prompt de la terminal, porque el prompt puede estar mal y esa comparación no.

Un entorno recién creado trae pip y nada más. Todo lo que la máquina tenía instalado globalmente le es invisible, a propósito, y esa es la propiedad que se está comprando: dos proyectos que necesitan versiones distintas de la misma librería dejan de ser un problema que resolver.

Activar es una comodidad, la ruta es el hecho

Activar edita el PATH para que python signifique el intérprete del entorno. No pasa nada más, y por eso cada problema en esta área tiene la misma solución: dejar de depender de la activación y llamar al intérprete por su ruta. ./entorno/bin/python -m pip install requests funciona esté o no activado algo, en una tarea programada, en un Makefile, y dentro de un editor que abrió su propia terminal.

De ahí salen dos hábitos. Correr pip como python -m pip y no como pip, para que el pip que corre y el intérprete en el que instala no puedan discrepar. Y nunca instalar en el intérprete del sistema: en una máquina actual normalmente se va a negar, y donde no se niega, pone las dependencias del proyecto donde cualquier otro proyecto las va a ver.

Qué hace la corrida reproducible

python -m pip freeze imprime exactamente lo instalado con versiones exactas, cinco líneas para la instalación de arriba, empezando por certifi==2026.7.22. Guardar eso es el mínimo: sin ello, la próxima persona recibe lo que estuviera vigente el día que corrió la instalación, y el reporte de error empieza con dos conjuntos de versiones distintos.

La forma actual es mejor que una lista congelada, porque una lista congelada no distingue las dependencias directas de las cuatro que llegaron de arrastre. Declarar requests en pyproject.toml y dejar que una herramienta escriba el archivo de bloqueo conserva esa distinción, así que actualizar una cosa no exige saber cuál de los cinco nombres era el que en verdad se pidió.

Qué usar en 2026

uv es la herramienta a la que se movió la mayoría de los proyectos de Python en 2026, gratis y de código abierto. Crea el entorno, resuelve e instala, y escribe un archivo de bloqueo, en un solo programa donde antes hacían falta tres, y es lo bastante rápido como para que recrear el entorno deje de ser algo que la gente evita. Reemplazó la combinación de venv, pip y pip-tools, y la nota honesta es que python -m venv y python -m pip siempre están presentes.

pyproject.toml es el archivo, gratis con el ecosistema y el estándar desde 2026. Reemplazó a setup.py y a la convención suelta de requirements.txt, y la ganancia práctica es que las dependencias declaradas y las resueltas quedan en dos archivos distintos.

Dónde se atasca esto

Este es el tropiezo de toda esta sección, apareciendo temprano: alguien que ya sabe escribir Python se encuentra con un entorno que no instala, concluye que es malo programando, y en realidad se está topando con el empaquetado, que nadie le dijo que era un tema aparte. Lo es, tiene su propio vocabulario, y toma una quincena y no una tarde.

El hábito que quita la mayor parte: antes de que cualquier otra cosa falle, correr python -c "import sys; print(sys.executable)" y leer con qué intérprete se está hablando en realidad. Casi toda instalación que no funcionó es esa ruta siendo distinta de la que corre el código.

Qué módulos revisar antes de instalar algo nuevo está en la biblioteca estándar, cómo se empaqueta un proyecto entero para no tener que reconstruir el entorno está en contenedores, y qué corre exactamente cuando el intérprete arranca está en cómo corre el código.

Al lado de esto

Arriba de esto