Cuando ejecutas python -m venv .venv, Python no instala nada nuevo ni descarga nada de internet. Lo que hace es construir un directorio con una estructura muy concreta que engaña al intérprete para que crea que ese es su hogar. Entender esa estructura te da control real sobre qué pasa cuando algo falla, y te explica por qué los entornos virtuales son tan ligeros y desechables.
La estructura interna
Después de crear el entorno, ábrelo y fíjate en lo que hay:
.venv/ ├── bin/ # (Scripts/ en Windows) │ ├── python # symlink o copia del intérprete │ ├── python3 │ ├── pip │ └── activate # el script que ya conoces ├── include/ # cabeceras C para extensiones nativas ├── lib/ │ └── python3.x/ │ └── site-packages/ # aquí van tus paquetes └── pyvenv.cfg # el archivo de configuración clave
El archivo pyvenv.cfg es el cerebro de todo esto. Un ejemplo real:
home = /usr/bin include-system-site-packages = false version = 3.11.4
home apunta al intérprete del sistema del que deriva este entorno. Cuando Python arranca dentro del entorno, lee este archivo, encuentra home, y sabe exactamente cuál es su identidad: soy un intérprete aislado que tiene su propio site-packages pero que viene de ahí.
site-packages es el directorio donde pip instala los paquetes. Sin entorno virtual, ese directorio estaría en algún lugar global del sistema (/usr/lib/python3.x/site-packages). Con el entorno, cada proyecto tiene el suyo propio, completamente independiente.
Qué pasa realmente al activar
source .venv/bin/activate no es magia: es un script de shell que hace dos cosas concretas en tu sesión actual.
# Lo que activate hace por dentro (simplificado) export VIRTUAL_ENV="/ruta/a/tu/proyecto/.venv" export PATH="$VIRTUAL_ENV/bin:$PATH"
VIRTUAL_ENV es una variable de entorno que herramientas como pip, pytest, y algunos IDEs usan para saber si estás dentro de un entorno. PATH se modifica anteponiendo .venv/bin/, lo que significa que cuando escribes python o pip, el shell encuentra primero los del entorno —no los del sistema.
No se cambia nada permanente en tu sistema. Solo se modifica el PATH de esa terminal, de esa sesión. Abre otra pestaña y no estará activado.
Por qué deactivate no borra nada
deactivate es una función de shell definida por activate que simplemente restaura PATH a su valor anterior (guardado en $_OLD_VIRTUAL_PATH) y elimina VIRTUAL_ENV. El directorio .venv sigue intacto. Puedes activar y desactivar el entorno mil veces sin que cambie un solo archivo dentro.
Esto tiene una implicación importante: el entorno virtual es solo un directorio. Puedes borrarlo con rm -rf .venv y recrearlo en segundos. No hay estado oculto, no hay registro en el sistema, no hay nada fuera de esa carpeta.
Ahora el ejemplo completo
# Primero, desde la terminal:
# python -m venv .venv
# source .venv/bin/activate (Linux/Mac)
# .venv\Scripts\activate (Windows)
import sys
import os
import site
def inspect_environment():
print("=== Intérprete activo ===")
# sys.executable muestra la ruta exacta del python que está corriendo
print(f"Python ejecutable: {sys.executable}")
print("\n=== Variable VIRTUAL_ENV ===")
virtual_env = os.environ.get("VIRTUAL_ENV", "No estás en un entorno virtual")
print(f"VIRTUAL_ENV: {virtual_env}")
print("\n=== Directorios de site-packages ===")
for path in site.getsitepackages():
print(f" {path}")
print("\n=== Primeras entradas del PATH ===")
path_entries = os.environ.get("PATH", "").split(os.pathsep)
for entry in path_entries[:4]:
print(f" {entry}")
if __name__ == "__main__":
inspect_environment()
Ejecuta este script con el entorno activado y luego desactivado. Verás exactamente cómo cambia sys.executable y VIRTUAL_ENV.
Lo que el código te muestra
sys.executable es el indicador más fiable de si estás usando el intérprete del entorno. Si apunta a algo dentro de .venv/, todo está bien. Si apunta a /usr/bin/python3, o instalaste en el lugar equivocado, o el entorno no está activado.
site.getsitepackages() devuelve la lista de directorios donde Python busca paquetes instalados. Con el entorno activado, el primer resultado debería ser .venv/lib/python3.x/site-packages. Ahí es donde pip install requests pondrá los archivos —y donde solo tu proyecto los verá.
os.environ.get("VIRTUAL_ENV") te da la ruta completa al entorno. Muchas herramientas usan esto para detectar automáticamente si deben usar el pip y el python del entorno.
La opción --system-site-packages
python -m venv --system-site-packages .venv
Esto cambia una línea en pyvenv.cfg:
include-system-site-packages = true
Con ese cambio, Python busca paquetes primero en .venv/site-packages y, si no los encuentra ahí, sigue buscando en los site-packages globales del sistema. Es útil cuando tienes instalado algo pesado a nivel de sistema (como numpy compilado con BLAS optimizado) y no quieres reinstalarlo en cada entorno. El riesgo es que introduces dependencias implícitas que otros colaboradores no tendrán si crean el entorno en otra máquina.
Errores que debes conocer
Error: Ejecutar pip install sin activar el entorno e instalar paquetes en el sistema global sin darte cuenta.
# ❌ Incorrecto — pip del sistema, no del entorno pip install requests # ✅ Correcto — activa primero, luego instala source .venv/bin/activate pip install requests
Comprueba siempre con which pip (o where pip en Windows) que apunta a .venv/bin/pip antes de instalar.
Error: Commitear .venv/ al repositorio git por olvidar añadirlo a .gitignore.
# ❌ Incorrecto — el entorno contiene binarios y rutas absolutas git add .venv/ # ✅ Correcto — solo se versiona la lista de dependencias echo ".venv/" >> .gitignore pip freeze > requirements.txt git add requirements.txt
El directorio .venv contiene rutas absolutas específicas de tu máquina y binarios compilados. No es portable: hay que regenerarlo en cada entorno de desarrollo.
Error: Confundir “entorno activado” con “Python configurado correctamente en el IDE”. Algunos editores (VS Code, PyCharm) ignoran el PATH de la terminal y usan su propio intérprete configurado.
# ❌ Asumes que el IDE usa el entorno activado en terminal import requests # ImportError aunque lo hayas instalado en .venv # ✅ Apunta el intérprete del IDE explícitamente a: # .venv/bin/python3 (en la configuración del proyecto)
En VS Code, usa Python: Select Interpreter y elige el que está dentro de .venv/.
N° 70