W3docs

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 os

No 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: /tmp

Listar 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.json

Nunca 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 path

Obtener 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.json

Esto 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=8080

Establecer 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 present

Establecer 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())   # hello

subprocess.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ónQué 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.environMapeo 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 sys

Argumentos 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.py

Modificar 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ónQué devuelve
sys.argvLista de argumentos de línea de comandos
sys.versionCadena de versión de Python
sys.version_infoTupla con nombre de (major, minor, micro, ...)
sys.platformIdentificador de plataforma ("linux", "darwin", "win32")
sys.pathRuta de búsqueda de módulos (lista de cadenas)
sys.modulesDiccionario de todos los módulos importados actualmente
sys.stdinFlujo de entrada estándar
sys.stdoutFlujo de salida estándar
sys.stderrFlujo 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.maxsizeValor 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.

TareaEstilo osEstilo pathlib
Unir rutasos.path.join(a, b)Path(a) / b
Obtener nombre de archivoos.path.basename(p)Path(p).name
Obtener extensiónos.path.splitext(p)[1]Path(p).suffix
Verificar si existeos.path.exists(p)Path(p).exists()
Leer archivo de textoopen(p).read()Path(p).read_text()
Listar directorioos.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

Práctica
Which function returns the current working directory in Python?
Which function returns the current working directory in Python?
Práctica
What does sys.argv[0] contain when you run a Python script from the command line?
What does sys.argv[0] contain when you run a Python script from the command line?

Capítulos relacionados

Was this page helpful?