Módulos os y sys de Python
Domina los módulos os y sys de Python: navega el sistema de archivos, gestiona variables de entorno, inspecciona el intérprete y maneja argumentos de línea de comandos.
Los módulos os y sys son dos de las herramientas más esenciales de la biblioteca estándar de Python. os conecta Python con el sistema operativo subyacente — permitiéndote navegar directorios, inspeccionar y establecer variables de entorno, y manipular archivos y rutas. sys conecta Python con el intérprete mismo — exponiendo la lista de argumentos, la ruta de búsqueda de módulos y ganchos para controlar la salida del intérprete. Juntos cubren casi todo lo que un script necesita para interactuar con el entorno en el que se ejecuta.
El módulo os
Importa os al inicio de tu script:
import osNo se necesita instalación; viene incluido en todas las distribuciones de Python.
Trabajo con directorios
Obtener y cambiar el directorio de trabajo actual
os.getcwd() devuelve la ruta absoluta del directorio donde se está ejecutando tu script. os.chdir() lo cambia.
import os
# Print the current directory
print(os.getcwd())
# Example output: /Users/alice/projects
# Change to a different directory
os.chdir("/tmp")
print(os.getcwd())
# Output: /tmpListar el contenido de un directorio
os.listdir(path) devuelve una lista de todas las entradas (archivos y subdirectorios) en path. No recurre en los subdirectorios.
import os
entries = os.listdir(".") # "." means current directory
for entry in sorted(entries):
print(entry)Para distinguir archivos de directorios usa os.path.isfile() y os.path.isdir():
import os
for entry in os.listdir("."):
if os.path.isdir(entry):
print(f"[DIR] {entry}")
else:
print(f"[FILE] {entry}")Crear y eliminar directorios
import os
# Create a single directory
os.mkdir("reports")
# Create nested directories in one call
os.makedirs("data/2024/january", exist_ok=True)
# exist_ok=True prevents an error if the directory already exists
# Remove an empty directory
os.rmdir("reports")
# Remove a full directory tree
import shutil
shutil.rmtree("data")El parámetro exist_ok=True en os.makedirs() es muy útil en scripts que pueden ejecutarse más de una vez — sin él, una segunda ejecución lanza FileExistsError.
Recorrer un árbol de directorios
os.walk(top) genera una tupla de tres elementos (dirpath, dirnames, filenames) para cada directorio en el árbol con raíz en top. Es la forma estándar de recorrer de forma recursiva una estructura de carpetas.
import os
for dirpath, dirnames, filenames in os.walk("project"):
level = dirpath.count(os.sep)
indent = " " * level
print(f"{indent}{os.path.basename(dirpath)}/")
for filename in filenames:
print(f"{indent} {filename}")Trabajo con rutas de archivos
El submódulo os.path de Python contiene utilidades portables de manipulación de rutas que funcionan correctamente en Windows, macOS y Linux.
Combinar componentes de ruta
os.path.join() combina partes de una ruta usando el separador correcto para el sistema operativo actual.
import os
base = "/home/alice"
project = "myapp"
filename = "config.json"
full_path = os.path.join(base, project, filename)
print(full_path)
# Output: /home/alice/myapp/config.jsonNunca construyas rutas con concatenación de cadenas como base + "/" + filename — se rompe en Windows. Usa siempre os.path.join().
Dividir una ruta
import os
path = "/home/alice/myapp/config.json"
print(os.path.dirname(path)) # /home/alice/myapp
print(os.path.basename(path)) # config.json
print(os.path.split(path)) # ('/home/alice/myapp', 'config.json')
print(os.path.splitext(path)) # ('/home/alice/myapp/config', '.json')os.path.splitext() es conveniente cuando necesitas eliminar o cambiar una extensión de archivo.
Comprobar si existe una ruta
import os
print(os.path.exists("/tmp")) # True (usually)
print(os.path.isfile("/tmp")) # False — it is a directory
print(os.path.isdir("/tmp")) # True
print(os.path.isabs("/tmp")) # True — it is an absolute pathObtener la ruta absoluta
os.path.abspath() resuelve rutas relativas respecto al directorio de trabajo actual:
import os
print(os.path.abspath("config.json"))
# Example output: /home/alice/myapp/config.jsonEsto es útil cuando necesitas almacenar o registrar una ruta que debe seguir siendo válida incluso si el directorio de trabajo cambia más adelante.
La variable __file__ y rutas relativas al script
Un error común: un script que abre "data.csv" funciona cuando lo ejecutas desde su propio directorio, pero falla desde uno diferente. La solución es construir la ruta relativa al propio archivo del script:
import os
# Directory that contains *this* script
HERE = os.path.dirname(os.path.abspath(__file__))
data_file = os.path.join(HERE, "data.csv")
with open(data_file, encoding="utf-8") as f:
content = f.read()Esta técnica hace que los scripts sean portables independientemente del directorio desde el que los ejecutes.
Variables de entorno
Las variables de entorno almacenan configuración que vive fuera del código fuente — URLs de bases de datos, claves de API, indicadores de características, etc. El mapeo os.environ te da acceso de lectura y escritura al entorno del proceso actual.
Leer una variable de entorno
import os
# Returns the value or None if not set
home = os.environ.get("HOME")
print(home)
# Example output: /home/alice
# Raise KeyError if not set (useful to fail fast on missing config)
path = os.environ["PATH"]Prefiere os.environ.get(key) sobre os.environ[key] a menos que la variable sea estrictamente necesaria y el programa deba fallar sin ella.
Leer con un valor predeterminado
import os
debug = os.environ.get("DEBUG", "false")
port = int(os.environ.get("PORT", "8080"))
print(f"debug={debug}, port={port}")
# Output: debug=false, port=8080Establecer y eliminar variables de entorno
import os
# Set a variable — affects only the current process and its children
os.environ["MY_APP_ENV"] = "production"
# Remove a variable
os.environ.pop("MY_APP_ENV", None) # None prevents KeyError if not presentEstablecer valores en os.environ no persiste después de que el proceso termina. Para establecer variables de entorno permanentes, modifica tu perfil de shell (~/.bashrc, ~/.zshrc) o usa un archivo .env cargado por una biblioteca como python-dotenv.
Listar todas las variables de entorno
import os
for key, value in sorted(os.environ.items()):
print(f"{key}={value}")Ejecutar comandos de shell con os.system() y subprocess
os.system(command) ejecuta un comando de shell y devuelve su código de salida, pero no te da ninguna forma de capturar su salida. Para cualquier cosa más allá de una llamada rápida de disparar y olvidar, usa el módulo subprocess en su lugar.
import os
import subprocess
# Quick way — exit code only
exit_code = os.system("echo hello")
print("exit code:", exit_code) # 0 means success
# Better way — capture output
result = subprocess.run(
["echo", "hello"],
capture_output=True,
text=True,
)
print(result.stdout.strip()) # hellosubprocess.run() es más potente y seguro que os.system() porque evita el intérprete de shell y te permite capturar stdout, stderr y el código de retorno como objetos Python.
Utilidades útiles de os
| Función | Qué hace |
|---|---|
os.getcwd() | Directorio de trabajo actual |
os.chdir(path) | Cambiar el directorio de trabajo |
os.listdir(path) | Listar entradas del directorio |
os.mkdir(path) | Crear un directorio |
os.makedirs(path, exist_ok=True) | Crear directorios anidados |
os.rmdir(path) | Eliminar un directorio vacío |
os.remove(path) | Eliminar un archivo |
os.rename(src, dst) | Renombrar / mover un archivo |
os.walk(top) | Recorrer recursivamente un árbol de directorios |
os.environ | Mapeo de variables de entorno |
os.getpid() | ID del proceso actual |
os.cpu_count() | Número de núcleos lógicos de CPU |
El módulo sys
sys expone información sobre el intérprete de Python y te proporciona ganchos para controlar su comportamiento.
import sysArgumentos de línea de comandos con sys.argv
sys.argv es una lista de cadenas. sys.argv[0] es el nombre del script; los elementos siguientes son los argumentos pasados en la línea de comandos.
Supón que guardas esto como greet.py y ejecutas python greet.py Alice 42:
import sys
script_name = sys.argv[0] # 'greet.py'
name = sys.argv[1] # 'Alice'
age = sys.argv[2] # '42' — always a string
print(f"Hello, {name}! You are {age} years old.")
# Output: Hello, Alice! You are 42 years old.Valida siempre sys.argv antes de acceder a los índices — un IndexError bloqueará el script si el usuario olvida un argumento:
import sys
if len(sys.argv) != 3:
print(f"Usage: python {sys.argv[0]} <name> <age>")
sys.exit(1)
name = sys.argv[1]
age = sys.argv[2]
print(f"Hello, {name}! You are {age} years old.")Para el análisis de argumentos complejos, prefiere el módulo argparse de la biblioteca estándar — genera la salida de --help automáticamente.
Salir del intérprete con sys.exit()
sys.exit(code) lanza SystemExit y termina el intérprete. Por convención, el código de salida 0 significa éxito; cualquier valor distinto de cero señala un error.
import sys
answer = input("Continue? (y/n): ")
if answer.lower() != "y":
print("Goodbye!")
sys.exit(0)
print("Continuing...")Puedes capturar SystemExit en un bloque try/except si necesitas ejecutar limpieza antes de que el programa termine, pero normalmente la sentencia with (para manejadores de archivos, conexiones de red, etc.) gestiona la limpieza automáticamente.
Información de versión de Python
import sys
print(sys.version)
# Example: 3.10.15 (main, ...) [GCC 11.4.0]
print(sys.version_info)
# sys.version_info(major=3, minor=10, micro=15, ...)
# Guard against running on an unsupported Python version
if sys.version_info < (3, 8):
sys.exit("This script requires Python 3.8 or later.")sys.version_info es una tupla con nombre, por lo que puedes compararla directamente con una tupla de enteros.
La ruta de búsqueda de módulos (sys.path)
Cuando escribes import mymodule, Python busca en cada directorio de sys.path en orden hasta encontrar un archivo coincidente. La lista comienza con el directorio del script (o una cadena vacía para sesiones interactivas), seguido de las entradas de PYTHONPATH, y luego la biblioteca estándar y los paquetes del sitio.
import sys
for p in sys.path:
print(p)Puedes añadir a sys.path en tiempo de ejecución para importar módulos desde ubicaciones no estándar:
import sys
import os
# Add a sibling directory to the search path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "libs"))
import mymodule # now found in ./libs/mymodule.pyModificar sys.path es una solución rápida para el desarrollo local, pero para paquetes distribuibles usa pip y un pyproject.toml adecuado en su lugar.
Flujos estándar
sys.stdin, sys.stdout y sys.stderr son objetos similares a archivos conectados a los tres flujos estándar. Puedes redirigirlos para capturar o suprimir la salida.
import sys
# Write to stdout (same as print, but more explicit)
sys.stdout.write("Hello, stdout\n")
# Write to stderr (errors and diagnostics)
sys.stderr.write("Warning: something looks off\n")Un patrón común en los scripts es redirigir sys.stdout a un archivo para capturar toda la salida de print():
import sys
with open("output.log", "w", encoding="utf-8") as log:
original_stdout = sys.stdout
sys.stdout = log
print("This goes to the log file.")
sys.stdout = original_stdout
print("This goes back to the terminal.")Atributos útiles de sys
| Atributo / Función | Qué devuelve |
|---|---|
sys.argv | Lista de argumentos de línea de comandos |
sys.version | Cadena de versión de Python |
sys.version_info | Tupla con nombre de (major, minor, micro, ...) |
sys.platform | Identificador de plataforma ("linux", "darwin", "win32") |
sys.path | Ruta de búsqueda de módulos (lista de cadenas) |
sys.modules | Diccionario de todos los módulos importados actualmente |
sys.stdin | Flujo de entrada estándar |
sys.stdout | Flujo de salida estándar |
sys.stderr | Flujo de error estándar |
sys.exit(code) | Salir del intérprete con el código de estado dado |
sys.getrecursionlimit() | Profundidad máxima de recursión (predeterminado 1000) |
sys.maxsize | Valor máximo de un int en esta plataforma |
Combinando os y sys en la práctica
Los scripts reales suelen usar ambos módulos juntos. Aquí hay un ejemplo pequeño pero realista: un script que escanea un directorio en busca de archivos .log e imprime un resumen.
import os
import sys
def summarize_logs(directory):
if not os.path.isdir(directory):
sys.stderr.write(f"Error: '{directory}' is not a directory.\n")
sys.exit(1)
log_files = [
f for f in os.listdir(directory)
if f.endswith(".log") and os.path.isfile(os.path.join(directory, f))
]
if not log_files:
print("No .log files found.")
return
print(f"Found {len(log_files)} log file(s) in '{directory}':")
for name in sorted(log_files):
full_path = os.path.join(directory, name)
size = os.path.getsize(full_path)
print(f" {name} ({size} bytes)")
if len(sys.argv) != 2:
print(f"Usage: python {sys.argv[0]} <directory>")
sys.exit(1)
summarize_logs(sys.argv[1])Ejecútalo como python summarize.py /var/log e imprimirá el nombre y el tamaño en bytes de cada archivo .log en ese directorio.
os vs pathlib — ¿Cuál deberías usar?
Python 3.4 introdujo pathlib.Path, una alternativa orientada a objetos de os.path. Ambos enfoques son correctos; la elección es principalmente una preferencia de estilo.
| Tarea | Estilo os | Estilo pathlib |
|---|---|---|
| Unir rutas | os.path.join(a, b) | Path(a) / b |
| Obtener nombre de archivo | os.path.basename(p) | Path(p).name |
| Obtener extensión | os.path.splitext(p)[1] | Path(p).suffix |
| Verificar si existe | os.path.exists(p) | Path(p).exists() |
| Leer archivo de texto | open(p).read() | Path(p).read_text() |
| Listar directorio | os.listdir(p) | list(Path(p).iterdir()) |
pathlib tiende a producir código más legible para scripts con muchas rutas; os.path es familiar y está soportado en todos los lugares donde se ejecuta Python 3. El módulo sys no tiene equivalente en pathlib — siempre es import sys.
Práctica
Capítulos relacionados
- Módulos de Python — crear e importar tus propios módulos
- Manejo de archivos en Python — leer y escribir archivos
- Try Except en Python — manejar errores de operaciones de archivos y del sistema operativo
- Variables de Python — alcance y nomenclatura de variables
- Alcance en Python — cómo Python resuelve nombres en diferentes ámbitos