Cuando instalas Python “directamente” —ya sea desde python.org, Homebrew o el gestor de paquetes de tu distro— estás poniendo una única versión en el sistema. El problema aparece en cuanto tienes dos proyectos: uno que necesita 3.9 porque depende de una librería que todavía no soporta 3.12, y otro que quiere lo último para aprovechar el tomllib de la stdlib. Con la instalación tradicional, uno de los dos pierde.
pyenv resuelve exactamente eso: te permite instalar varias versiones de Python en tu máquina y elegir cuál usa cada proyecto, cada directorio, o incluso cada sesión de terminal, sin que ninguna de ellas interfiera con el Python del sistema operativo.
Por dentro: shims y el PATH
La magia de pyenv no es magia, es una manipulación deliberada de cómo el shell resuelve comandos. Cuando instalas pyenv, añades ~/.pyenv/shims al principio de tu PATH. Ahí viven unos ejecutables ligeros llamados shims: pequeños scripts que interceptan cualquier llamada a python, pip, pytest, o cualquier otro binario de Python.
Cuando escribes python script.py, el shim se activa antes que cualquier Python real. Entonces pyenv consulta, en este orden:
- La variable de entorno
PYENV_VERSION(si está definida). - El archivo
.python-versionen el directorio actual, subiendo por el árbol hasta encontrar uno. - La versión global configurada en
~/.pyenv/version.
Con esa información decide qué Python real ejecutar y delega. Tú no ves nada de esto; solo ves que python --version devuelve algo diferente según en qué directorio estés.
pyenv rehash es el comando que regenera los shims. Cada vez que instalas una nueva versión (o un paquete que instala un binario, como pytest o black), tienes que ejecutarlo para que pyenv se entere de los nuevos ejecutables. Las versiones modernas de pyenv hacen esto automáticamente en muchos casos, pero saber qué es rehash te evita la confusión de “instalé el paquete pero el comando no se encuentra”.
Si usas el activador incorrecto en el .bashrc/.zshrc o no antepones shims al PATH, pyenv se instala pero nunca toma el control: el sistema seguirá usando el Python nativo y los comandos de selección no tendrán efecto ninguno.
Los cuatro comandos que usarás siempre
# Instala Python 3.11.9 (compila desde fuente, tarda unos minutos) pyenv install 3.11.9 # Lista todas las versiones disponibles para instalar pyenv install --list # Lista las versiones que ya tienes instaladas pyenv versions # Establece la versión global (fallback para cualquier directorio sin .python-version) pyenv global 3.12.3 # Escribe un .python-version en el directorio actual pyenv local 3.11.9 # Afecta solo a la sesión de terminal actual (no toca ningún archivo) pyenv shell 3.9.19
El archivo .python-version que genera pyenv local es texto plano con el nombre de la versión. Deberías commitearlo junto con tu código: cualquier colaborador que tenga pyenv instalado obtendrá automáticamente la versión correcta al entrar al directorio.
Un flujo real de trabajo
# Este archivo no es código Python; es la estructura de directorios # que vamos a crear para demostrar pyenv en acción. # Lo que sigue son comandos de shell y su salida esperada.
# Situación: proyecto legacy en 3.9, proyecto nuevo en 3.12 mkdir ~/projects/legacy && cd ~/projects/legacy pyenv local 3.9.19 python --version # Python 3.9.19 ← pyenv leyó .python-version mkdir ~/projects/nuevo && cd ~/projects/nuevo pyenv local 3.12.3 python --version # Python 3.12.3 # De vuelta al legacy, sin hacer nada: cd ~/projects/legacy python --version # Python 3.9.19 ← cambió automáticamente
Ahora combinamos versión con entorno virtual usando pyenv-virtualenv, el plugin oficial:
# Crear un virtualenv llamado "legacy-env" basado en Python 3.9.19 pyenv virtualenv 3.9.19 legacy-env # Activarlo automáticamente al entrar al directorio cd ~/projects/legacy pyenv local legacy-env # .python-version ahora contiene "legacy-env" # Verificar que estamos en el entorno correcto python --version # Python 3.9.19 pip list # solo paquetes instalados en legacy-env
Qué hace cada pieza
pyenv install descarga el código fuente de CPython y lo compila localmente en ~/.pyenv/versions/<version>/. Por eso necesitas tener las dependencias de compilación instaladas (gcc, zlib, openssl, etc.) antes de empezar; si no las tienes, el error que obtienes a veces es críptico.
pyenv global 3.12.3 escribe ese string en ~/.pyenv/version. Es el último recurso: cuando ningún directorio padre tiene .python-version y no hay PYENV_VERSION definida, pyenv usa ese archivo. Si no lo configuras y el sistema no tiene Python instalado de otra forma, obtendrás un error.
pyenv local es el comando que más vas a usar en el día a día. El .python-version que genera actúa como documentación ejecutable: cualquiera que clone tu repositorio y tenga pyenv sabrá exactamente qué versión usar sin leer ningún README.
pyenv shell es útil para pruebas rápidas (“quiero correr este script puntualmente con 3.10 sin tocar nada”) porque solo vive en la sesión actual.
pyenv-virtualenv combina los dos mundos: gestión de versión más aislamiento de paquetes. Cuando haces pyenv local legacy-env, el shim no solo resuelve la versión de Python sino también activa el virtualenv, por lo que pip install va al lugar correcto sin que tengas que recordar ejecutar source .venv/bin/activate nunca más.
Errores que debes conocer
Error: pyenv está instalado pero python --version sigue mostrando el Python del sistema. Ocurre porque la línea de inicialización no está en el archivo correcto del shell, o está después de otras líneas que manipulan el PATH.
# ❌ Wrong: pyenv no está al inicio del PATH, o falta la inicialización export PATH="$HOME/.pyenv/bin:$PATH" # (sin la línea de eval) # ✅ Right: inicialización completa en ~/.bashrc o ~/.zshrc export PYENV_ROOT="$HOME/.pyenv" export PATH="$PYENV_ROOT/bin:$PATH" eval "$(pyenv init -)" eval "$(pyenv virtualenv-init -)" # si usas pyenv-virtualenv
eval "$(pyenv init -)" es lo que registra los shims; sin esa línea, el binario de pyenv existe pero nunca intercepta los comandos de Python.
Error: pyenv install 3.12.3 falla con errores de compilación sobre zlib u openssl. Pasa porque pyenv compila CPython desde fuente y necesita las cabeceras del sistema.
# ❌ Wrong: intentar instalar sin las dependencias pyenv install 3.12.3 # BUILD FAILED: ...zlib not available # ✅ Right: instalar dependencias primero (Ubuntu/Debian) sudo apt-get install -y build-essential libssl-dev zlib1g-dev \ libbz2-dev libreadline-dev libsqlite3-dev libffi-dev pyenv install 3.12.3
Las dependencias exactas varían por sistema operativo; la wiki de pyenv tiene la lista para cada uno.
Error: commitear .python-version con el nombre de un virtualenv personal (legacy-env) en lugar de la versión de Python (3.9.19). Tus colaboradores no tienen ese virtualenv, así que pyenv falla al entrar al directorio.
# ❌ Wrong: el .python-version apunta a un virtualenv local echo "legacy-env" > .python-version # solo existe en tu máquina # ✅ Right: la versión de Python en el repo; el virtualenv lo crea cada quien echo "3.9.19" > .python-version # esto sí funciona en cualquier máquina con pyenv
El virtualenv personal va en .gitignore; la versión de Python va en el repositorio.
N° 10