Python Módulo 1 – Primeros pasos: instalar, ejecutar y leer Python
Entornos virtuales con venv y pip
Crea un entorno virtual de Python con venv, instala y lista paquetes en él con python -m pip, y descubre por qué muchos Python del sistema rechazan pip install.
Qué vas a aprender
- Crear, activar y borrar un entorno virtual con venv
- Instalar, listar y quitar paquetes con python -m pip
- Detectar desde un programa si se ejecuta en un entorno virtual
- Explicar por qué muchos Python del sistema rechazan pip install
- Reconstruir un entorno a partir de requirements.txt en lugar de moverlo
Antes de empezar
Qué vas a aprender · Antes de empezar
Qué vas a aprender
- Crear, activar y borrar un entorno virtual con venv
- Instalar, listar y quitar paquetes con python -m pip
- Detectar desde un programa si se ejecuta en un entorno virtual
- Explicar por qué muchos Python del sistema rechazan pip install
- Reconstruir un entorno a partir de requirements.txt en lugar de moverlo
Antes de empezar
En esta página
Dos proyectos en una misma computadora pueden necesitar dos versiones del mismo paquete, uno escrito para la versión 1 de una biblioteca y otro para la versión 2. Con un único Python, un solo pip install sirve a los dos, así que una actualización para un proyecto puede romper el otro, y el Python que vino con tu sistema operativo también puede ejecutar herramientas del propio sistema. Un entorno virtual da a cada proyecto una carpeta de paquetes propia.
A continuación creas un entorno y miras dentro, ves qué cambia al activarlo, instalas un paquete en él sin descargar nada, ves por qué muchos Python del sistema rechazan un pip install sin más, y reconstruyes un entorno en lugar de moverlo. Todas las órdenes se ejecutaron con el Python 3.14.8 de este curso, y la página muestra exactamente lo que imprimieron.
Un entorno virtual es una carpeta con sus propios paquetes
Un entorno virtual es una carpeta, por convención llamada .venv y guardada en la propia carpeta del proyecto. Dentro importan tres cosas:
pyvenv.cfg, un pequeño archivo de texto que nombra el Python a partir del cual se creó el entorno, su Python base;bin/python(Scripts\python.exeen Windows), la propia ordenpythondel entorno;lib/python3.14/site-packages(Lib\site-packagesen Windows), adonde van los paquetes que instalas para este proyecto.
Qué hay dentro de un entorno virtual
Descripción en texto del diagrama
El diagrama muestra, de arriba abajo, una carpeta de proyecto y, debajo y fuera de ella, el Python base.
- La carpeta del proyecto contiene tu propio código, main.py, y el entorno virtual, una carpeta llamada .venv.
- main.py se ejecuta con la propia orden python del entorno, bin/python (Scripts\python.exe en Windows).
- Ese python lee pyvenv.cfg e importa los paquetes de la carpeta site-packages del entorno (lib/python3.14/site-packages, o Lib\site-packages en Windows), donde pip instala los paquetes de este proyecto.
- pyvenv.cfg nombra el Python 3.14 base a partir del cual se creó el entorno. El python del entorno es un enlace a ese intérprete (en Windows, un pequeño lanzador que lo inicia) y usa su biblioteca estándar: solo los paquetes pertenecen al entorno.
Crea uno con python3 -m venv .venv en la carpeta del proyecto, o py -m venv .venv en Windows. -m venv ejecuta el módulo venv del Python que escribiste, así que el entorno se construye sobre ese Python y mantiene su versión. La orden no imprime nada cuando funciona. En Debian necesita antes un paquete más: Debian distribuye venv en un paquete propio, python3-venv, y la documentación de Ubuntu incluye venv entre lo que añade su paquete python3-full. Este programa crea un entorno y mira dentro:
look_inside.py
import sys
from pathlib import Path
from session import run
# The environment's programs are in .venv/bin (.venv\Scripts on Windows).
run("python3 -m venv .venv", sys.executable, "-m", "venv", ".venv")
print("In .venv:", sorted(p.name for p in Path(".venv").iterdir()))
print("pyvenv.cfg says:")
print(Path(".venv/pyvenv.cfg").read_text(), end="")
packages = Path(".venv/lib/python3.14/site-packages")
print("site-packages holds:", sorted(p.name for p in packages.iterdir()))
print(".gitignore holds:", Path(".venv/.gitignore").read_text().splitlines()[-1])
check = "import sys; print(sys.prefix != sys.base_prefix)"
run(f".venv/bin/python -c '{check}'", ".venv/bin/python", "-c", check)
run(f"python3 -c '{check}'", sys.executable, "-c", check) Salida
$ python3 -m venv .venv In .venv: ['.gitignore', 'bin', 'include', 'lib', 'pyvenv.cfg'] pyvenv.cfg says: home = …/bin include-system-site-packages = false version = 3.14.8 executable = …/bin/python3.14 command = …/bin/python3 -m venv .venv site-packages holds: ['pip', 'pip-26.2.1.dist-info'] .gitignore holds: * $ .venv/bin/python -c 'import sys; print(sys.prefix != sys.base_prefix)' True $ python3 -c 'import sys; print(sys.prefix != sys.base_prefix)' False
Salida registrada con Python 3.14.8 en macOS 26 arm64. Para ejecutarlo tú: mise exec python@3.14.8 -- python3 look_inside.py
session.py
"""Runs a command as if you had typed it in a terminal, and prints what it printed."""
import os
import subprocess
# PIP_DISABLE_PIP_VERSION_CHECK: pip does not look online for a newer pip,
# so what these examples print does not depend on the network.
ENV = {**os.environ, "PIP_DISABLE_PIP_VERSION_CHECK": "1"}
def run(typed, *command):
"""Show the command as you would type it, run it, and print its output."""
print("$", typed)
result = subprocess.run(command, capture_output=True, text=True, env=ENV)
print(result.stdout + result.stderr, end="")
return result Hay cuatro cosas que ver en esa salida. La biblioteca estándar no se copió: site-packages solo contiene pip, el único paquete con el que empieza un entorno nuevo, en la versión que incluye este Python, 26.2.1. pyvenv.cfg nombra la carpeta del Python base en home (la página acorta esa carpeta a …), y include-system-site-packages = false deja fuera los paquetes propios del Python base. venv escribió un .gitignore que contiene *, así que Git ignora toda la carpeta, cosa que venv hace desde Python 3.13. Y sys.prefix != sys.base_prefix es True dentro del entorno y False fuera: la documentación de venv da esta comparación como la forma de que un programa lo sepa.
¿Cómo sabe .venv/bin/python que pertenece a un entorno? Recorre un arranque y una importación:
El dibujo muestra la escena completa; sus 6 pasos aparecen abajo.
Todos los pasos en texto
- Inicias .venv/bin/python. En macOS y Linux, .venv/bin/python suele ser un enlace al intérprete del Python base (en Windows, un pequeño lanzador que lo inicia), así que lo que se ejecuta es el intérprete base.
- Encuentra pyvenv.cfg. Al arrancar, Python busca pyvenv.cfg junto a su programa y una carpeta más arriba. Encuentra .venv/pyvenv.cfg, así que sys.prefix pasa a ser .venv mientras que sys.base_prefix sigue siendo el Python base.
- La biblioteca estándar se comparte. json, pathlib y el resto de la biblioteca estándar siguen viniendo del Python base, y por eso crear un entorno tarda segundos y no copia ninguno de ellos.
- Los paquetes vienen de .venv. Los paquetes se buscan en la propia carpeta site-packages del entorno, así que se puede importar todo lo que pip instaló en este entorno.
- Los paquetes base se quedan fuera. pyvenv.cfg dice include-system-site-packages = false, así que no se busca en la carpeta site-packages propia del Python base. Un paquete instalado ahí es invisible aquí.
- Un proyecto, un conjunto de paquetes. El .venv de otro proyecto tiene su propio site-packages y el mismo Python base. Los dos comparten el intérprete y la biblioteca estándar, y nunca los paquetes del otro.
Idea clave
Un entorno virtual es una carpeta de paquetes con un pyvenv.cfg que apunta a un Python base: el intérprete y la biblioteca estándar son los del Python base, y solo los paquetes pertenecen al entorno.
Punto de control
Comprueba: qué es un entorno virtual
Activarlo pone el python del entorno el primero en PATH
Typing .venv/bin/python every time is long. Activating the environment puts its bin folder (Scripts on
Windows) first on your PATH: The environment variable that lists the folders a shell searches, in order, for a command you type. A command whose folder is not on PATH answers "command not found" until the folder is added or the full path is typed., so that python, python3 and pip mean the
environment’s until you type deactivate or close the terminal. Here is a bash shell before, during and after:
import subprocess
import sys
from session import run
run("python3 -m venv .venv", sys.executable, "-m", "venv", ".venv")
# The commands below run in one bash shell, one after another, as if typed.
commands = [
"command -v python3",
"source .venv/bin/activate",
"command -v python3",
'echo "$PS1"',
"deactivate",
"command -v python3",
]
script = "".join(f"echo '$ {line}'; {line}\n" for line in commands)
shell = subprocess.run(["bash", "-c", script], capture_output=True, text=True)
print(shell.stdout + shell.stderr, end="") Salida
$ python3 -m venv .venv $ command -v python3 …/bin/python3 $ source .venv/bin/activate $ command -v python3 .venv/bin/python3 $ echo "$PS1" (.venv) $ deactivate $ command -v python3 …/bin/python3
Salida registrada con Python 3.14.8 en macOS 26 arm64. Para ejecutarlo tú: mise exec python@3.14.8 -- python3 activate_session.py
Antes de activar, python3 era el Python base, el de este curso (acortado a …). Después de source .venv/bin/activate, el shell encontró primero .venv/bin/python3, y el indicador empezaba por (.venv), que es como puedes ver que hay un entorno activo. deactivate devolvió las dos cosas a su estado. La orden para activar depende de tu shell:
| Shell | Se activa con |
|---|---|
| bash o zsh (macOS, Linux) | source .venv/bin/activate |
| fish | source .venv/bin/activate.fish |
| csh o tcsh | source .venv/bin/activate.csh |
| PowerShell (Windows) | .venv\Scripts\Activate.ps1 |
| Símbolo del sistema (Windows) | .venv\Scripts\activate.bat |
Si PowerShell se niega a ejecutar Activate.ps1, la documentación de venv da la orden que permite esos scripts para tu propio usuario: Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser.
Activar es una comodidad, no un requisito. La ruta completa del intérprete del entorno ejecuta un programa en el entorno sin activar nada: .venv/bin/python main.py, o .venv\Scripts\python main.py en Windows. Así es como usan un entorno los editores y las tareas programadas.
Punto de control
Comprueba: activar un entorno
pip instala en el entorno del python que lo ejecuta
python -m pip ejecuta el pip de ese python, así que instala en el entorno de ese python. El programa de abajo primero construye un pequeño archivo de paquete, un wheel: Un paquete construido, un archivo zip con la extensión .whl, a menudo uno por plataforma. pip instala un wheel desempaquetando sus archivos, sin ejecutar el código del propio paquete. Más en “Buscar e instalar paquetes de terceros” (en inglés) hecho por make_wheel.py, para que la instalación no necesite descargar nada: --no-index --find-links wheels le dice a pip que busque solo en esa carpeta. Instalar desde PyPI: El Python Package Index, pypi.org, donde se publican la mayoría de los paquetes de Python de terceros. pip instala desde él salvo que se le diga que use otro índice o una carpeta de archivos. Más en “Buscar e instalar paquetes de terceros” (en inglés) funciona igual, con una descarga:
install_session.py
import sys
from make_wheel import make_wheel
from session import run
make_wheel("wheels") # a package file to install from, so no download is needed
py = ".venv/bin/python"
run("python3 -m venv .venv", sys.executable, "-m", "venv", ".venv")
run(f"{py} -m pip --version", py, "-m", "pip", "--version")
run(
f"{py} -m pip install --no-index --find-links wheels marksheet",
py, "-m", "pip", "install", "--no-index", "--find-links", "wheels", "marksheet",
)
run(f"{py} -m pip list", py, "-m", "pip", "list")
where = "import marksheet; print(marksheet.__file__)"
run(f"{py} -c '{where}'", py, "-c", where)
run("python3 -c 'import marksheet'", sys.executable, "-c", "import marksheet")
run(f"{py} -m pip uninstall -y marksheet", py, "-m", "pip", "uninstall", "-y", "marksheet") Salida
$ python3 -m venv .venv
$ .venv/bin/python -m pip --version
pip 26.2.1 from .venv/lib/python3.14/site-packages/pip (python 3.14)
$ .venv/bin/python -m pip install --no-index --find-links wheels marksheet
Looking in links: wheels
Processing ./wheels/marksheet-1.0.0-py3-none-any.whl
Installing collected packages: marksheet
Successfully installed marksheet-1.0.0
$ .venv/bin/python -m pip list
Package Version
--------- -------
marksheet 1.0.0
pip 26.2.1
$ .venv/bin/python -c 'import marksheet; print(marksheet.__file__)'
.venv/lib/python3.14/site-packages/marksheet.py
$ python3 -c 'import marksheet'
Traceback (most recent call last):
File "<string>", line 1, in <module>
import marksheet
ModuleNotFoundError: No module named 'marksheet'
$ .venv/bin/python -m pip uninstall -y marksheet
Found existing installation: marksheet 1.0.0
Uninstalling marksheet-1.0.0:
Successfully uninstalled marksheet-1.0.0
Salida registrada con Python 3.14.8 en macOS 26 arm64. Para ejecutarlo tú: mise exec python@3.14.8 -- python3 install_session.py
make_wheel.py
"""Builds marksheet-1.0.0-py3-none-any.whl, a tiny package, so that no download is needed.
A wheel is a zip file: the package's code, and a NAME-VERSION.dist-info folder that
says what the package is and which commands it adds.
"""
import base64
import hashlib
import zipfile
from pathlib import Path
CODE = '''def grade(mark):
return "pass" if mark >= 35 else "fail"
def main():
print("72 is a", grade(72))
'''
def make_wheel(folder):
info = "marksheet-1.0.0.dist-info"
files = {
"marksheet.py": CODE,
f"{info}/METADATA": "Metadata-Version: 2.4\nName: marksheet\nVersion: 1.0.0\n",
f"{info}/WHEEL": "Wheel-Version: 1.0\nGenerator: make_wheel.py\nRoot-Is-Purelib: true\nTag: py3-none-any\n",
f"{info}/entry_points.txt": "[console_scripts]\nmarksheet = marksheet:main\n",
}
record = []
for name, text in files.items():
digest = base64.urlsafe_b64encode(hashlib.sha256(text.encode()).digest())
record.append(f"{name},sha256={digest.rstrip(b'=').decode()},{len(text.encode())}")
files[f"{info}/RECORD"] = "\n".join(record + [f"{info}/RECORD,,"]) + "\n"
Path(folder).mkdir(exist_ok=True)
wheel = Path(folder, "marksheet-1.0.0-py3-none-any.whl")
with zipfile.ZipFile(wheel, "w") as archive:
for name, text in files.items():
archive.writestr(name, text)
return wheel pip --version nombra la carpeta desde la que se ejecuta su pip, el site-packages del entorno, y el paquete también acabó ahí, como .venv/lib/python3.14/site-packages/marksheet.py. Así que el python del entorno lo importa, y el python3 base se detiene con ModuleNotFoundError: ese aislamiento es para lo que sirve un entorno virtual. Con el entorno activo, un python -m pip sin más significa lo mismo:
| Tarea | Orden |
|---|---|
| Instalar un paquete | python -m pip install requests |
| Instalar un rango de versiones | python -m pip install "requests>=2,<3" |
| Actualizar un paquete | python -m pip install --upgrade requests |
| Listar lo que hay instalado | python -m pip list |
| Quitar un paquete | python -m pip uninstall requests |
| Guardar las versiones exactas | python -m pip freeze > requirements.txt |
| Instalar desde ese archivo | python -m pip install -r requirements.txt |
Pon entre comillas un rango de versiones, como en la segunda fila: sin las comillas, el shell lee < y > como redirecciones. Como mostró la lección del REPL, python -m pip también asegura que se ejecuta el pip del intérprete correcto, mientras que un pip sin más puede pertenecer a otro Python de tu PATH.
Seguridad
A package you install runs its code on your computer whenever your program uses it. Check the spelling of the name and the project’s page on pypi.org before you install: with typosquatting: Registering a package name one slip away from a popular one, such as a letter dropped, two letters swapped or a separator removed, so that a typo installs someone else's code., a name one slip away from a popular package, a typo installs someone else’s code.
Punto de control
Comprueba: instalar en un entorno
Muchos Python del sistema rechazan pip install fuera de un entorno
Ejecuta python3 -m pip install requests con el Python de Debian 12 o posterior, o con el de Homebrew en un Mac, fuera de cualquier entorno, y pip se detiene con error: externally-managed-environment y This environment is externally managed. Ese Python pertenece al gestor de paquetes del sistema, que instala él mismo sus paquetes; un pip install podría sustituir un paquete que necesita una herramienta del sistema. La regla es un estándar de empaquetado, de la PEP 668. Recorre la comprobación que hace pip 26.2.1 antes de instalar:
El dibujo muestra la escena completa; sus 6 pasos aparecen abajo.
Todos los pasos en texto
- Fuera de cualquier entorno. Ejecutas python3 -m pip install requests con el Python de Debian 12 o de Homebrew, sin ningún entorno virtual activo.
- Primera pregunta. pip pregunta si se ejecuta dentro de un entorno virtual, comparando sys.prefix con sys.base_prefix. Aquí son la misma carpeta, así que la respuesta es no.
- Segunda pregunta. Busca un archivo llamado EXTERNALLY-MANAGED en la carpeta de la biblioteca estándar. El gestor de paquetes del sistema puso uno ahí, para decir que él mismo instala los paquetes de este Python.
- pip se niega. pip se detiene con error: externally-managed-environment y muestra el mensaje de ese archivo, que normalmente dice que crees un entorno virtual. No se instaló ni se cambió nada.
- Dentro de un entorno virtual. Ejecuta la misma orden con .venv/bin/python y la primera respuesta es sí. pip instala en el entorno y nunca busca el archivo, y por eso un entorno siempre funciona.
- Un Python sin el archivo. Un Python sin ese archivo, como el de este curso instalado con mise, deja que pip instale, pero en el único Python base que comparten todos los proyectos. Un entorno sigue siendo mejor sitio.
Un programa puede hacer la misma comprobación que hace pip. El Python 3.14.8 de este curso lo instaló un gestor de versiones, mise, no el gestor de paquetes de un sistema, así que todas las respuestas son False: nada lo marca como gestionado.
import sys
import sysconfig
from pathlib import Path
in_venv = sys.prefix != sys.base_prefix
marker = Path(sysconfig.get_path("stdlib"), "EXTERNALLY-MANAGED")
print("Python", sys.version.split()[0])
print("Inside a virtual environment:", in_venv)
print("Marked as externally managed:", marker.exists())
print("A plain pip install would be refused:", marker.exists() and not in_venv) Salida
Python 3.14.8 Inside a virtual environment: False Marked as externally managed: False A plain pip install would be refused: False
Salida registrada con Python 3.14.8 en macOS 26 arm64. Para ejecutarlo tú: mise exec python@3.14.8 -- python3 managed.py
Ejecuta el mismo archivo con el python3 de Debian 12 o de Homebrew y la tercera línea dice True, igual que la cuarta, salvo que lo ejecutes desde un entorno virtual, donde pip siempre puede instalar. Cuando te encuentres con el error:
- Para todo lo que importa tu propio código, crea un entorno virtual, como en esta lección.
- Para una aplicación de línea de órdenes que quieres tener en todas partes, instálala con pipx, la herramienta de la lección siguiente, que da a cada aplicación un entorno propio.
- Para una biblioteca que empaqueta el propio sistema, instala el paquete del sistema con su gestor de paquetes, como sugiere el mensaje del Python de Debian (
apt install python3-xyz).
Atención
No uses sudo pip install, y mantente lejos de la opción --break-system-packages de pip, que, como dice su documentación, permite que pip modifique una instalación gestionada externamente. Las dos cosas cambian archivos de los que dependen las herramientas del propio sistema operativo.
Punto de control
Comprueba: Python del sistema que rechazan pip
Borra y reconstruye un entorno, nunca lo muevas
No hay nada tuyo en .venv, así que borrarlo es seguro: elimina la carpeta (rm -rf .venv en macOS y Linux, Remove-Item -Recurse .venv en PowerShell, o con tu gestor de archivos). Antes, anota las versiones exactas en un archivo de requisitos: Un archivo de texto, normalmente requirements.txt, con un requisito por línea, que instala pip install -r. pip freeze escribe uno que enumera cada paquete instalado con su versión exacta. Más en “Buscar e instalar paquetes de terceros” (en inglés) con pip freeze, para que un entorno nuevo pueda volver a tener los mismos paquetes.
Lo que rompe las cosas es moverlo. Cada orden que instala pip, como marksheet abajo, es un pequeño script cuya primera línea, #!, contiene la ruta completa del python del entorno, así que después de moverlo esa ruta ya no existe. El programa muestra el ciclo completo, de congelar a reconstruir:
import os
import shutil
import subprocess
import sys
from pathlib import Path
from make_wheel import make_wheel
from session import run
def first_line(script):
"""Where the #! line of a script that pip installed points, and whether that python exists."""
python = script.read_text().splitlines()[0].removeprefix("#!")
print(f" {script} starts with #! and the full path of {os.path.relpath(python)};",
"it exists:", Path(python).exists())
make_wheel("wheels")
py = ".venv/bin/python"
find = ["--no-index", "--find-links", "wheels"]
run("python3 -m venv .venv", sys.executable, "-m", "venv", ".venv")
run(f"{py} -m pip install --no-index --find-links wheels marksheet", py, "-m", "pip", "install", *find, "marksheet")
frozen = run(f"{py} -m pip freeze", py, "-m", "pip", "freeze").stdout
Path("requirements.txt").write_text(frozen) # what pip freeze > requirements.txt does
first_line(Path(".venv/bin/marksheet"))
print("$ mv .venv moved")
shutil.move(".venv", "moved")
first_line(Path("moved/bin/marksheet"))
print("$ moved/bin/marksheet")
try:
subprocess.run(["moved/bin/marksheet"], check=True)
except FileNotFoundError as error: # the python its #! line names is gone
print(" it does not start:", error.strerror)
print("$ rm -rf moved")
shutil.rmtree("moved")
run("python3 -m venv .venv", sys.executable, "-m", "venv", ".venv")
run(f"{py} -m pip install --no-index --find-links wheels -r requirements.txt",
py, "-m", "pip", "install", *find, "-r", "requirements.txt")
run(".venv/bin/marksheet", ".venv/bin/marksheet") Salida
$ python3 -m venv .venv $ .venv/bin/python -m pip install --no-index --find-links wheels marksheet Looking in links: wheels Processing ./wheels/marksheet-1.0.0-py3-none-any.whl Installing collected packages: marksheet Successfully installed marksheet-1.0.0 $ .venv/bin/python -m pip freeze marksheet==1.0.0 .venv/bin/marksheet starts with #! and the full path of .venv/bin/python; it exists: True $ mv .venv moved moved/bin/marksheet starts with #! and the full path of .venv/bin/python; it exists: False $ moved/bin/marksheet it does not start: No such file or directory $ rm -rf moved $ python3 -m venv .venv $ .venv/bin/python -m pip install --no-index --find-links wheels -r requirements.txt Looking in links: wheels Processing ./wheels/marksheet-1.0.0-py3-none-any.whl (from -r requirements.txt (line 1)) Installing collected packages: marksheet Successfully installed marksheet-1.0.0 $ .venv/bin/marksheet 72 is a pass
Salida registrada con Python 3.14.8 en macOS 26 arm64. Para ejecutarlo tú: mise exec python@3.14.8 -- python3 move_and_rebuild.py
La orden movida seguía nombrando .venv/bin/python, que ya no existía, así que no arrancó (la página escribe esa ruta completa relativa a la carpeta del ejemplo). El entorno reconstruido a partir de requirements.txt vuelve a funcionar, con el mismo marksheet 1.0.0. La documentación de venv dice lo mismo: los entornos no se pueden mover ni copiar, así que se vuelven a crear en el nuevo lugar.
Subir o copiar .venv
Meter .venv en Git, o copiarlo a otra computadora, distribuye una carpeta llena de rutas que solo tienen sentido en la computadora que la creó. Sube requirements.txt (o el pyproject.toml del proyecto, que presenta la lección siguiente) y deja que cada persona construya su propio entorno a partir de él.
Punto de control
Comprueba: reconstruir en lugar de mover
Practica: comprobar un entorno
Dos funciones cortas usan las ideas de esta lección: una dice si un programa se ejecuta en un entorno virtual, y la otra lee las versiones que anotó pip freeze. Los dos pasos vienen con código inicial, una primera pista y pruebas de ejemplo que puedes ejecutar aquí en la página, así que hazlos en el orden que quieras:
Laboratorio de código · 2 pasos
Comprobar un entorno
Averigua si un Python se ejecuta en un entorno virtual, y después lee las versiones exactas que anotó pip freeze.
- Averiguar si un Python se ejecuta en un entorno virtual Por hacer
- Leer las versiones que anotó pip freeze Por hacer
Ejercicio · Fácil · Python
Averiguar si un Python se ejecuta en un entorno virtual
Escribe in_virtualenv(sys_module). Recibe un objeto con los atributos prefix y base_prefix, como el propio módulo sys, y devuelve True cuando el Python que describe se ejecuta dentro de un entorno virtual y False cuando es un Python base.
- Dentro de un entorno,
prefixes la carpeta del entorno ybase_prefixla del Python base, así que son distintas. - En un Python base son la misma carpeta.
- Las pruebas pasan objetos falsos además del
sysreal, así que lee los atributos desys_module, no los desys.
Código inicial · venvcheck.py
def in_virtualenv(sys_module):
"""Return True if the Python that sys_module describes runs in a virtual environment."""
return None Las pruebas de ejemplo · test_venvcheck.py
import sys
from types import SimpleNamespace
from venvcheck import in_virtualenv
def test_inside_an_environment():
"""a prefix that differs from base_prefix means a virtual environment"""
fake = SimpleNamespace(prefix="/home/asha/marks/.venv", base_prefix="/usr")
assert in_virtualenv(fake) is True
def test_base_python():
"""the same prefix and base_prefix means the base Python itself"""
fake = SimpleNamespace(prefix="/usr", base_prefix="/usr")
assert in_virtualenv(fake) is False
def test_windows_paths():
"""works the same with Windows paths"""
fake = SimpleNamespace(prefix="C:\\marks\\.venv", base_prefix="C:\\Python314")
assert in_virtualenv(fake) is True
def test_this_python():
"""agrees with the sys module of the Python that runs the tests"""
assert in_virtualenv(sys) == (sys.prefix != sys.base_prefix) Una pista
Toda la comprobación es una comparación de sys_module.prefix con sys_module.base_prefix. La comparación ya da True o False, así que devuélvela directamente.
Resultados de las pruebas de ejemplo
| Prueba | Resultado | Detalles |
|---|
Lo que imprimió tu código
Las pruebas de ejemplo se ejecutan en este dispositivo, en tu navegador (Pyodide): no se envía nada a mysmartcopilot.com. La primera ejecución descarga Python (unos 13.5 MB), que se guarda para las siguientes. Una comprobación en tu navegador es una orientación para ti, no la prueba de que el código sea correcto con cualquier entrada.
Ejercicio · Fácil · Python
Leer las versiones que anotó pip freeze
Escribe pinned_versions(text). text es lo que imprimió pip freeze (el contenido de un requirements.txt), y la función devuelve un dict que asocia el nombre de cada paquete con su versión exacta.
- Una línea como
marksheet==1.0.0da{"marksheet": "1.0.0"}. - Las líneas vacías y los comentarios (las líneas que empiezan por
#) se saltan, igual que los espacios alrededor de una línea. - Un paquete instalado directamente desde un archivo aparece como
marksheet @ file:///…/marksheet-1.0.0-py3-none-any.whl#sha256=…, sin==: sáltate también esa línea, porque anota un archivo, no una versión. - Un texto vacío da un dict vacío.
Código inicial · frozen.py
def pinned_versions(text):
"""Return {name: version} for every name==version line of pip freeze's output."""
versions = {}
return versions Las pruebas de ejemplo · test_frozen.py
from frozen import pinned_versions
def test_two_pins():
"""reads every name==version line"""
text = "marksheet==1.0.0\ntablekit==2.3.1\n"
assert pinned_versions(text) == {"marksheet": "1.0.0", "tablekit": "2.3.1"}
def test_blank_lines_and_comments():
"""skips blank lines and comments"""
text = "# written by pip freeze\n\nmarksheet==1.0.0\n"
assert pinned_versions(text) == {"marksheet": "1.0.0"}
def test_spaces_around_a_line():
"""ignores spaces around a line"""
assert pinned_versions(" marksheet==1.0.0 \n") == {"marksheet": "1.0.0"}
def test_a_file_instead_of_a_version():
"""skips a line that records a file instead of a version"""
text = "marksheet @ file:///home/asha/wheels/marksheet-1.0.0-py3-none-any.whl\ntablekit==2.3.1\n"
assert pinned_versions(text) == {"tablekit": "2.3.1"}
def test_empty_text():
"""gives an empty dict for empty text"""
assert pinned_versions("") == {} Una pista
Recorre text.splitlines(), aplica strip() a cada línea y usa continue cuando está vacía, empieza por # o no tiene ==. Después, line.split("==", 1) da el nombre y la versión.
Resultados de las pruebas de ejemplo
| Prueba | Resultado | Detalles |
|---|
Lo que imprimió tu código
Las pruebas de ejemplo se ejecutan en este dispositivo, en tu navegador (Pyodide): no se envía nada a mysmartcopilot.com. La primera ejecución descarga Python (unos 13.5 MB), que se guarda para las siguientes. Una comprobación en tu navegador es una orientación para ti, no la prueba de que el código sea correcto con cualquier entrada.
Cuando pasen los dos pasos, prueba las preguntas de abajo. Eligen la idea de esta lección que menos dominas, y la explicación de una opción equivocada dice qué se le escapa:
Práctica que se adapta a ti
Practica esta lección
11 preguntas sobre 5 ideas de esta lección. Cada respuesta se explica al momento, y lo que aciertas se guarda en este navegador.
Preguntas de entrevista
Calentamiento (júnior): ¿qué es un entorno virtual, y por qué usar uno para cada proyecto?
Un entorno virtual es una carpeta, normalmente .venv dentro del proyecto, con su propia orden python y su propia carpeta site-packages, creada por python3 -m venv .venv. Su pyvenv.cfg apunta al Python base, cuyo intérprete y biblioteca estándar usa, así que solo los paquetes son suyos. Un entorno por proyecto significa que cada proyecto tiene exactamente las versiones que necesita: uno puede usar la versión 1 de una biblioteca mientras otro usa la 2, una actualización en uno no puede romper el otro, y el propio Python del sistema queda intacto. El entorno se puede borrar y reconstruir a partir de requirements.txt en cualquier momento, y por eso nunca se sube al repositorio: se sube la lista de paquetes, no la carpeta.
Dos preguntas más difíciles parten de esta lección: un servidor que rechaza pip install, y una tarea programada que no encuentra un paquete que tu terminal sí encuentra. Piensa tu primer paso antes de abrir cada una:
Las respuestas modelo se abren con cualquier pase: 79 ₹ por 1 semana (2,99 US$), un solo pago que nunca se renueva.
-
De júnior a nivel medio
En un servidor nuevo con Debian 12, python3 -m pip install falla con error: externally-managed-environment. Un compañero sugiere sudo pip install --break-system-packages. ¿Qué haces en su lugar, para una aplicación web que ejecuta el servidor y para una herramienta de línea de órdenes que usas allí, y por qué?
-
De júnior a nivel medio
pip install requests funcionó en tu terminal, y tu script se ejecuta ahí. El mismo script, iniciado por una tarea programada cada noche, se detiene con ModuleNotFoundError: No module named 'requests'. Explica por qué y arréglalo para que no pueda volver a pasar.
Para recordar
- Un entorno virtual es una carpeta (
.venv) con su propiopythony su propiosite-packages, construida sobre un Python base cuyo intérprete y biblioteca estándar comparte; créalo conpython3 -m venv .venv, opy -m venv .venven Windows. - Activar pone la carpeta
bindel entorno la primera enPATH;.venv/bin/pythonejecuta un programa en el entorno sin activar nada. python -m pipinstala en el entorno del python que lo ejecuta, y solo ahí, y por eso el Python base no puede importar el paquete.error: externally-managed-environmentsignifica que el Python pertenece al sistema: usa un entorno virtual o pipx, nuncasudo pipni--break-system-packages.- Anota las versiones exactas con
pip freeze > requirements.txt, y reconstruye un entorno a partir de ese archivo en lugar de moverlo o copiarlo, porque los scripts instalados contienen su ruta completa. sys.prefix != sys.base_prefixle dice a un programa que se ejecuta dentro de un entorno virtual.
Referencias
- El tutorial de Python: entornos virtuales y paquetes (en inglés) (Python Software Foundation)
- venv, creación de entornos virtuales (en inglés) (Python Software Foundation)
- La inicialización de la ruta de búsqueda de módulos sys.path (en inglés) (Python Software Foundation)
- site, el gancho de configuración específica del sitio (en inglés) (Python Software Foundation)
- Instalar paquetes en un entorno virtual con pip y venv (en inglés) (Python Packaging Authority)
- pip install (documentación de pip 26.2.1, en inglés) (Python Packaging Authority)
- Entornos gestionados externamente (especificación, en inglés) (Python Packaging Authority)
- PEP 668: marcar los entornos base de Python como gestionados externamente (en inglés) (Python Software Foundation)
- Código fuente de pip 26.2.1: el error externally-managed-environment (en inglés) (Python Packaging Authority)
- Notas de la versión de Debian 12: intérpretes de Python marcados como externally-managed (en inglés) (Debian)
- Ubuntu para desarrolladores: configurar Python (en inglés) (Canonical)
- Homebrew: entornos de lenguajes y paquetes (en inglés) (Homebrew)
Herramientas relacionadas
Informar de un problema con esta lección (en inglés)
Solo se guarda en este navegador. Tu progreso en Learn (en inglés)