Contenido del curso
Fundamentos de Python
Los fundamentos de Python incluyen la sintaxis (sangría para bloques de código), los tipos de datos básicos (numéricos, booleanos, cadenas de texto), las variables, el control de flujo (condicionales como if/elif/else y bucles como for/while), y las funciones (bloques de código reutilizables).
0/6
Operadores y Control de Flujo
Los operadores en Python se clasifican en varios tipos (aritméticos, de comparación, lógicos, de asignación, etc.), mientras que el control de flujo se refiere al orden en que se ejecutan las instrucciones, modificándolo con estructuras como if, elif, else (condicionales), y for o while (bucles). Las instrucciones break, continue y pass también controlan el flujo dentro de los bucles.
0/3
Funciones y Manejo de Errores
Las funciones en Python son bloques de código reutilizables, mientras que el manejo de errores (excepciones) se hace con los bloques try, except, else y finally para gestionar errores de ejecución y evitar que el programa se detenga abruptamente. try ejecuta un código, except lo captura si ocurre un error específico, else se ejecuta si no hay error y finally se ejecuta siempre, haya o no error.
0/3
Estructuras de Datos
Las estructuras de datos principales en Python son las listas, tuplas, diccionarios y conjuntos. Estos tipos de datos se diferencian por su mutabilidad (si sus elementos se pueden cambiar después de su creación) y si mantienen el orden de los elementos. Las listas son ordenadas y mutables, mientras que las tuplas son ordenadas e inmutables. Los diccionarios son colecciones no ordenadas de pares clave-valor, y los conjuntos son colecciones desordenadas de elementos únicos.
0/5
Programación Orientada a Objetos (POO)
La Programación Orientada a Objetos (POO) en Python es un paradigma que organiza el código en torno a objetos, que son instancias de clases. Las clases actúan como plantillas que definen los atributos (datos) y métodos (comportamientos) de los objetos, permitiendo crear programas más modularizados, reutilizables y fáciles de mantener. Python soporta conceptos clave de la POO como la herencia, el encapsulamiento y el polimorfismo.
0/5
Ambientes virtuales
Un entorno virtual de Python es un espacio aislado que permite instalar paquetes y dependencias específicos para un proyecto concreto sin afectar a otras aplicaciones o a la instalación global de Python. Se crea una carpeta con una instalación de Python y una copia local de pip dentro de este entorno, lo que permite a cada proyecto tener sus propias bibliotecas y versiones, evitando así conflictos entre diferentes proyectos que puedan requerir versiones distintas de la misma librería.
0/1
Archivos
El manejo de archivos en Python se realiza principalmente usando la función open() para abrir un archivo y los métodos read(), write(), append() y close() para manipularlo. Es crucial gestionar los archivos adecuadamente, cerrándolos para liberar recursos, aunque es más recomendable usar la sentencia with, que cierra el archivo automáticamente. Python permite trabajar con archivos de texto y binarios, así como con distintos modos de apertura como 'r' (solo lectura), 'w' (escritura/sobreescritura), y 'a' (añadir).
0/1
Módulos y Librerías Estándar
Un "módulo" en Python se refiere a dos conceptos distintos: un archivo .py con código que se puede importar para reutilizar funciones, clases y variables, y el operador % que calcula el residuo de una división entera. Ambos son útiles para organizar el código y resolver problemas matemáticos, respectivamente.
0/2
Hilos y tareas en Python
En Python, los hilos (threads) son secuencias de ejecución dentro de un proceso que permiten la concurrencia, ejecutando tareas simultáneamente para aprovechar mejor los recursos del sistema. Las tareas son las unidades de trabajo a realizar, como descargar archivos o procesar datos. Se utilizan para manejar operaciones que implican espera (I/O-bound) de forma eficiente, permitiendo que una aplicación no se bloquee mientras espera. Para ello, se usa el módulo threading, se crean objetos Thread que representan las tareas, se inician con .start() y se pueden sincronizar con mecanismos como Lock para evitar conflictos.
0/1
Curso de Programación en Pythón 3.

    🖨️ Fundamentos de print()

    En esta primera parte aprenderás a usar una de las funciones más importantes de Python: print().
    Con ella podrás mostrar mensajes, resultados de operaciones y cualquier información en pantalla.
    Es la base de toda interacción entre el programa y el usuario.


    📦 Sintaxis básica y múltiple

    La función print() se utiliza para imprimir texto o valores en la consola.

    print("Hola, mundo!")

    Salida:

    
    Hola, mundo!
    

    También puedes imprimir varios elementos separados por comas:

    print("El resultado es", 10 + 5)

    Salida:

    
    El resultado es 15
    

    💡 Python convierte automáticamente los valores numéricos, cadenas o booleanos a texto al usar print(), por lo que no necesitas transformarlos con str().


    📋 Tabla resumen — Uso básico de print()

    EjemploSalidaDescripción
    print("Hola")HolaImprime una cadena de texto
    print(2 + 3)5Evalúa una operación aritmética
    print("Edad:", 30)Edad: 30Combina texto y números
    print(True)TrueImprime un valor booleano

    ⚙️ Parámetros sep y end

    La función print() tiene dos parámetros muy útiles:

    • sep: define el separador entre los elementos.
    • end: define lo que se imprime al final de la línea (por defecto es un salto de línea \n).

    Ejemplo con sep:

    print("Python", "es", "genial", sep="-")

    Salida:

    
    Python-es-genial
    

    Ejemplo con end:

    print("Hola", end=" ")
    print("mundo!")

    Salida:

    
    Hola mundo!
    

    💡 sep y end se usan mucho cuando quieres controlar el formato exacto del texto.


    📁 Parámetros avanzados: file y flush

    Por defecto, print() escribe en la salida estándar (pantalla), pero puedes enviarlo a un archivo usando file=.

    with open("salida.txt", "w") as archivo:
        print("Guardando texto en un archivo.", file=archivo)
    

    Esto crea (o sobrescribe) un archivo salida.txt con el texto dentro.

    🌀 El parámetro flush

    Por rendimiento, la salida se almacena temporalmente en memoria (buffer).
    Si quieres forzar la escritura inmediata, usa flush=True:

    print("Procesando...", flush=True)

    Esto es útil cuando estás mostrando progreso en tiempo real (por ejemplo, en scripts largos o interfaces de consola).


    🔤 Secuencias de escape y saltos de línea

    Dentro de las cadenas puedes usar caracteres especiales que comienzan con una barra invertida (\).

    SecuenciaSignificadoEjemploSalida
    \nSalto de líneaprint("Hola\nMundo")Hola
    Mundo
    \tTabulaciónprint("A\tB\tC")A   B   C
    \\Imprime una barra invertidaprint("Ruta C:\\Archivos")Ruta C:\Archivos
    \"Comillas dobles dentro de textoprint("Ella dijo: \"Hola\"")Ella dijo: «Hola»

    También puedes usar cadenas raw (crudas) anteponiendo una r, para que no interprete los escapes:

    print(r"C:\nueva\carpeta")  # No interpreta \n como salto
    

    Salida:

    
    C:\nueva\carpeta
    

    🧩 Ejemplos prácticos con print()

    Ejemplo 1: Imprimir varios tipos de datos

    nombre = "Javier"
    edad = 32
    activo = True
    
    print("Usuario:", nombre, "| Edad:", edad, "| Activo:", activo)
    
    
    Usuario: Javier | Edad: 32 | Activo: True
    

    Ejemplo 2: Mostrar resultados de operaciones

    a, b = 5, 3
    print("Suma:", a + b)
    print("Multiplicación:", a * b)
    print("División:", a / b)
    
    
    Suma: 8
    Multiplicación: 15
    División: 1.6666666666666667
    

    Ejemplo 3: Uso combinado de sep y end

    print("Cargando", end="")
    for i in range(3):
        print(".", end="", flush=True)
    print(" ¡Listo!")
    
    
    Cargando... ¡Listo!
    

    📚 Resumen de la Parte 1

    • print() muestra información por pantalla o archivos.
    • Usa sep y end para personalizar la salida.
    • Los parámetros file y flush controlan la salida avanzada.
    • Las secuencias de escape permiten incluir saltos, tabulaciones o comillas.
    • Combina texto y variables fácilmente: print("Edad:", edad).


    ⬆️ Volver al índice

    🎨 Formateo y presentación de salida

    Imprimir “algo” funciona. Imprimirlo bonito y claro es otro nivel.
    En esta parte aprenderás a formatear salidas con f-strings (recomendado), str.format() y el estilo antiguo con %.
    También verás alineación, anchos fijos, precisión decimal, separadores de miles y cómo mostrar Unicode/emoji.


    💡 F-strings (recomendado)

    Las f-strings (desde Python 3.6) son la forma más clara y moderna de formatear texto.
    Se antepone una f a la cadena y se insertan expresiones entre llaves {}.

    nombre = "Javier"
    edad = 32
    print(f"Hola, {nombre}. Tienes {edad} años.")
    

    Las f-strings admiten expresiones y especificadores de formato tras dos puntos : dentro de las llaves.

    precio = 19.9876
    print(f"Precio: {precio:.2f} €")     # 2 decimales
    porcentaje = 0.2567
    print(f"Tasa: {porcentaje:.1%}")     # porcentaje con 1 decimal
    entero = 1234567
    print(f"Entero con miles: {entero:,}")  # separador de miles (,) → 1,234,567
    
    EspecificadorSignificadoEjemploSalida
    :.2f2 decimalesf"{3.14159:.2f}"3.14
    :.0f0 decimales (redondea)f"{9.8:.0f}"10
    :+dSigno para enterosf"{7:+d}"+7
    :08dAncho 8, relleno con 0f"{42:08d}"00000042
    :,Separador de milesf"{1234567:,}"1,234,567
    :.1%Porcentajef"{0.256:.1%}"25.6%
    :^10Alinear centrado (ancho 10)f"{'OK':^10}"   OK   

    También puedes usar expresiones y llamadas dentro de las llaves:

    def iva(precio, tasa=0.21):
        return precio * (1 + tasa)
    
    p = 50
    print(f"Total con IVA: {iva(p):.2f} €")  # Llama a la función dentro del formato
    

    🧩 Método str.format() y mini-lenguaje

    str.format() fue el estándar antes de las f-strings y sigue siendo útil.

    nombre = "Ana"
    edad = 28
    print("Hola, {}. Tienes {} años.".format(nombre, edad))
    print("Hola, {n}. Tienes {e} años.".format(n=nombre, e=edad))
    print("Precio: {:.2f} €".format(19.9876))
    

    Soporta índice de posición, nombres y especificadores idénticos a los de f-strings:

    print("{:>10}".format("OK"))   # Alineado a la derecha (ancho 10)
    print("{:^10}".format("OK"))   # Centrado
    print("{:<10}".format("OK"))   # Alineado a la izquierda
    print("{:08d}".format(42))     # 00000042
    print("{:,}".format(1234567))  # 1,234,567
    

    📼 Estilo antiguo con % (heredado)

    Menos recomendado, pero aún lo verás en código legacy.

    nombre = "Lucía"
    edad = 30
    print("Hola, %s. Tienes %d años." % (nombre, edad))
    print("Pi ≈ %.3f" % 3.1415926)
    
    MarcadorTipoEjemploSalida
    %scadena"%s" % "hola"hola
    %dentero"%d" % 77
    %.2ffloat (2 dec.)"%.2f" % 3.13.10

    📏 Ancho, alineación y precisión

    Formatear columnas ayuda a construir tablas legibles en consola.

    productos = [
        ("Manzanas", 3, 0.6),
        ("Peras", 12, 0.75),
        ("Plátanos", 100, 0.33),
    ]
    
    # Encabezado
    print(f"{'Producto':<12} {'Unidades':>8} {'Precio':>8}")
    print("-" * 30)
    
    # Filas
    for nombre, unidades, precio in productos:
        print(f"{nombre:<12} {unidades:>8d} {precio:>8.2f}")
    

    Salida aproximada:

    
    Producto        Unidades   Precio
    ------------------------------
    Manzanas              3     0.60
    Peras                12     0.75
    Plátanos            100     0.33
    

    Claves del mini-lenguaje (en f-strings y format()):

    PatrónSignificadoEjemplo
    {x:<10}Alinea a la izquierda, ancho 10f"{'OK':<10}"
    {x:>10}Alinea a la derecha, ancho 10f"{'OK':>10}"
    {x:^10}Centrado, ancho 10f"{'OK':^10}"
    {n:08d}Rellena con ceros (8)f"{42:08d}"
    {v:.3f}3 decimalesf"{3.14159:.3f}"
    {v:,}Separador de milesf"{1234567:,}"

    🌍 Unicode, acentos y emoji

    Python 3 usa UTF-8 por defecto en código fuente. Puedes imprimir acentos y emoji sin drama:

    print("Café ☕ — Precio: 2,50 €")
    print("Bandera España: \U0001F1EA\U0001F1F8")
    

    Si escribes a archivo y tienes lío de acentos, especifica encoding="utf-8":

    with open("salida.txt", "w", encoding="utf-8") as f:
        print("Café ☕ — Precio: 2,50 €", file=f)
    

    🖼️ Pretty print para estructuras (dict/list)

    Para diccionarios y listas complejas, usa pprint para una salida “bonita”.

    from pprint import pprint
    
    datos = {
        "usuario": "jcachon",
        "roles": ["admin", "editor", "report"],
        "perfil": {"nombre": "Javier", "activo": True, "edad": 32}
    }
    
    pprint(datos, sort_dicts=False, width=60)
    

    🧪 Casos prácticos

    1) Tickets y facturas

    lineas = [
        ("Teclado mecánico", 1, 79.9),
        ("Ratón inalámbrico", 2, 24.5),
        ("Alfombrilla XXL", 1, 17.9),
    ]
    
    print(f"{'Artículo':<20} {'Ud':>3} {'Precio':>8} {'Total':>8}")
    print("-" * 45)
    total = 0
    for art, ud, pr in lineas:
        t = ud * pr
        total += t
        print(f"{art:<20} {ud:>3d} {pr:>8.2f} {t:>8.2f}")
    
    print("-" * 45)
    print(f"{'TOTAL':>33} {total:>10.2f} €")
    

    2) Reportes con porcentaje y miles

    usuarios = 1234567
    crecimiento = 0.0342
    print(f"Usuarios: {usuarios:,} | Crecimiento: {crecimiento:.2%}")
    

    3) Tabla alineada con cabeceras

    cab = ("ID", "Nombre", "Score")
    rows = [(1, "Ana", 9.5), (23, "Luis", 7.25), (305, "Marta", 8.0)]
    
    print(f"{cab[0]:>4}  {cab[1]:<10}  {cab[2]:>6}")
    print("-" * 24)
    for i, n, s in rows:
        print(f"{i:>4d}  {n:<10}  {s:>6.2f}")
    

    ✅ Resumen

    • Usa f-strings para legibilidad y potencia ({expr:formato}).
    • str.format() sigue siendo válido; el estilo % es legacy.
    • Controla ancho, alineación, rellenos y precisión con el mini-lenguaje de formato.
    • Gestiona Unicode/emoji sin problemas; usa encoding="utf-8" en archivos.
    • pprint hace más legible la impresión de estructuras complejas.

    ⌨️ Fundamentos de input()

    La función input() es la herramienta básica para pedir información al usuario.
    Cada vez que se ejecuta, el programa se detiene y espera a que el usuario escriba algo en la consola.
    Cuando se presiona Enter, el texto ingresado se devuelve como una cadena (str).


    📥 Sintaxis básica y prompt

    Su sintaxis es muy sencilla:

    nombre = input("¿Cómo te llamas? ")
    print("Hola,", nombre)
    

    Cuando se ejecuta:

    
    ¿Cómo te llamas? Javier
    Hola, Javier
    

    El texto entre comillas dentro de input() es el prompt (mensaje que se muestra al usuario).

    💡 Si no se pasa ningún texto, el prompt estará vacío y el cursor parpadeará esperando entrada:

    dato = input()
    print("Has escrito:", dato)
    

    🔢 Conversión de tipos (casting)

    Todo lo que devuelve input() es una cadena.
    Si necesitas un número o un valor lógico, debes convertirlo explícitamente con las funciones de tipo.

    Tipo deseadoFunciónEjemploEntrada → Resultado
    Enteroint()int(input())“25” → 25
    Decimalfloat()float(input())“3.14” → 3.14
    Textostr()str(input())“Hola” → “Hola”
    Lógicobool()bool(input())⚠️ Siempre True si hay texto

    Ejemplo completo:

    edad = int(input("Introduce tu edad: "))
    print("El año que viene tendrás", edad + 1, "años.")
    

    Salida:

    
    Introduce tu edad: 32
    El año que viene tendrás 33 años.
    

    💡 Importante: si el usuario introduce algo no convertible (por ejemplo, letras en lugar de un número), se producirá un ValueError.
    Por eso, aprenderás en el siguiente punto cómo manejar esos errores con try/except.


    🧱 Validación y manejo de errores

    Es buena práctica asegurarse de que la entrada del usuario sea válida antes de usarla.
    El control de errores se hace con try/except.

    try:
        numero = int(input("Introduce un número entero: "))
        print("Has escrito el número", numero)
    except ValueError:
        print("❌ Error: Debes introducir un número válido.")
    

    Salida:

    
    Introduce un número entero: hola
    ❌ Error: Debes introducir un número válido.
    

    Validar rangos:

    try:
        edad = int(input("Edad: "))
        if edad < 0:
            print("❌ La edad no puede ser negativa.")
        elif edad > 120:
            print("⚠️ Edad poco realista.")
        else:
            print("✅ Edad registrada:", edad)
    except ValueError:
        print("❌ Introduce un número entero.")
    

    ✂️ Limpieza de entradas (strip, lower, upper)

    El texto introducido puede tener espacios, mayúsculas o caracteres indeseados.
    Python ofrece métodos útiles para “limpiar” la cadena antes de procesarla:

    MétodoFunciónEjemploResultado
    strip()Elimina espacios iniciales y finales" hola ".strip()"hola"
    lower()Convierte a minúsculas"PYTHON".lower()"python"
    upper()Convierte a mayúsculas"python".upper()"PYTHON"
    capitalize()Primera letra mayúscula"python".capitalize()"Python"

    Ejemplo:

    respuesta = input("¿Deseas continuar? (sí/no): ").strip().lower()
    if respuesta == "sí" or respuesta == "si":
        print("Continuando el programa...")
    else:
        print("Programa finalizado.")
    

    ⚙️ Lectura de múltiples valores

    También puedes pedir varios datos en una sola línea y separarlos con split().

    entrada = input("Introduce tres números separados por espacios: ")
    a, b, c = map(int, entrada.split())
    print("Suma:", a + b + c)
    

    Salida:

    
    Introduce tres números separados por espacios: 3 4 5
    Suma: 12
    

    💡 split() divide la cadena por espacios, pero puedes usar otro separador:

    # Con comas
    numeros = input("Introduce números separados por coma: ")
    lista = [int(x) for x in numeros.split(",")]
    print("Lista:", lista)
    
    
    Introduce números separados por coma: 5,10,15
    Lista: [5, 10, 15]
    

    🧠 Resumen de la Parte 3

    • input() pausa el programa y devuelve una cadena (str).
    • Usa funciones de conversión: int(), float(), str().
    • Controla errores con try/except para evitar bloqueos.
    • Limpia la entrada con strip(), lower() y similares.
    • Divide y procesa varios valores con split() o map().

    🤝 Flujo interactivo, seguridad y UX

    En esta parte aprenderás cómo crear programas que dialoguen con el usuario: pedir datos, validarlos, repetirlos si son incorrectos y hacerlo de manera clara y segura.
    Además, verás cómo proteger entradas sensibles (como contraseñas) y mejorar la experiencia general del usuario.


    🔁 Bucles de reintento y mensajes útiles

    Cuando el usuario comete un error al introducir un valor, lo ideal es volver a pedirlo sin que el programa se bloquee.
    Esto se consigue fácilmente con bucles while y control de errores.

    while True:
        try:
            edad = int(input("Introduce tu edad: "))
            if edad <= 0:
                print("⚠️ La edad debe ser un número positivo.")
            else:
                print(f"Perfecto, tienes {edad} años.")
                break
        except ValueError:
            print("❌ Error: Introduce un número válido.")
    

    💡 Este patrón se conoce como input loop: el usuario no puede avanzar hasta que proporcione una entrada válida.


    💬 Personalizando mensajes

    La claridad es clave. Usa frases amables y precisas.
    Evita mensajes genéricos o técnicos como “Error de tipo” o “Entrada inválida”.
    Un ejemplo más humano:

    while True:
        nombre = input("Escribe tu nombre: ").strip()
        if len(nombre) < 2:
            print("❌ El nombre es demasiado corto, inténtalo de nuevo.")
        else:
            print(f"Hola, {nombre}! Encantado de conocerte.")
            break
    

    🔒 Entradas sensibles con getpass

    Cuando necesitas solicitar contraseñas o datos confidenciales, nunca uses input().
    Python ofrece el módulo getpass que oculta la entrada del usuario mientras escribe.

    from getpass import getpass
    
    usuario = input("Usuario: ")
    clave = getpass("Contraseña: ")
    
    if usuario == "admin" and clave == "1234":
        print("✅ Acceso concedido.")
    else:
        print("❌ Acceso denegado.")
    

    💡 Al ejecutar este código en consola, los caracteres de la contraseña no se muestran ni siquiera con asteriscos —es la forma más segura y profesional de pedir contraseñas.


    🧱 Buenas prácticas de seguridad

    Las entradas del usuario pueden ser peligrosas si no se validan correctamente.
    Aquí tienes algunas reglas esenciales:

    • 🔸 Nunca uses eval() o exec() con texto ingresado por el usuario.
    • 🔸 Valida siempre el formato, longitud y contenido de los datos.
    • 🔸 En campos sensibles (contraseñas, tokens), utiliza getpass o cifrado.
    • 🔸 Si el programa manipula archivos, controla rutas y extensiones.

    Ejemplo de mala práctica ❌

    # ¡PELIGRO! No hagas esto
    expr = input("Escribe una expresión: ")
    print(eval(expr))  # Permite ejecutar código arbitrario
    

    Ejemplo de buena práctica ✅

    expr = input("Escribe una expresión matemática: ")
    try:
        resultado = float(eval(expr, {"__builtins__": None}, {}))  # Controla entorno
        print("Resultado:", resultado)
    except Exception:
        print("⚠️ Entrada no válida.")
    

    Aun así, lo mejor es implementar tus propias funciones de evaluación seguras (por ejemplo, con ast.literal_eval o expresiones regulares).


    🌍 Localización: separadores y formatos

    En distintos países, los números se escriben de forma diferente:
    por ejemplo, 3.14 frente a 3,14.
    Si esperas usuarios internacionales, puedes usar el módulo locale para gestionar formatos numéricos.

    import locale
    
    locale.setlocale(locale.LC_ALL, '')  # Usa la configuración regional del sistema
    numero = 12345.6789
    print("Número local:", locale.format_string("%.2f", numero, grouping=True))
    

    Esto mostrará el número con los separadores y decimales apropiados para la región del usuario.


    🧠 Patrones de prompts “amables”

    Una buena interfaz de texto debe ser amigable, coherente y minimalista.
    Aquí tienes algunos consejos prácticos:

    Mal prompt ❌Buen prompt ✅
    input("Edad: ")input("Por favor, introduce tu edad (en años): ")
    input("Sexo: ")input("Selecciona tu sexo (H/M): ")
    input("Clave: ")getpass("Introduce tu contraseña: ")

    Ejemplo final — diálogo completo

    from getpass import getpass
    
    print("=== Registro de usuario ===")
    
    while True:
        nombre = input("Nombre de usuario: ").strip()
        if len(nombre) < 3:
            print("⚠️ El nombre debe tener al menos 3 caracteres.")
            continue
    
        clave = getpass("Contraseña (mínimo 6 caracteres): ")
        if len(clave) < 6:
            print("⚠️ La contraseña es demasiado corta.")
            continue
    
        print(f"✅ Usuario {nombre} registrado correctamente.")
        break
    

    💬 Este tipo de flujo evita frustraciones y da al usuario un feedback inmediato y claro.


    📋 Resumen de la Parte 4

    • Repite entradas inválidas usando bucles while con validación.
    • Oculta contraseñas con getpass().
    • Evita funciones inseguras como eval() sin control.
    • Usa locale para mostrar números según la región.
    • Escribe prompts amables y descriptivos para mejorar la UX.

    🧰 I/O avanzado: streams, archivos y pruebas

    En esta parte subirás de nivel: trabajarás con flujos estándar (STDIN/STDOUT/STDERR), leerás y escribirás archivos, gestionarás codificaciones, redirigirás/capturarás salidas y aprenderás cuándo usar print() y cuándo logging.


    🧵 STDIN / STDOUT / STDERR con sys

    Python expone tres flujos estándar en el módulo sys:

    FlujoUsoCuándo
    sys.stdinEntrada estándarLeer datos (pipes, redirección, terminal)
    sys.stdoutSalida estándarMensajes normales / resultados
    sys.stderrSalida de erroresAlertas, trazas, advertencias
    import sys
    
    # Escribir sin salto de línea automático
    sys.stdout.write("Procesando")
    sys.stdout.write("...\n")
    
    # Mensaje de error (separado de la salida normal)
    sys.stderr.write("⚠️ Aviso: archivo no encontrado\n")
    

    💡 Separar stdout de stderr permite redirigirlos por separado en consola (p. ej., guardar solo resultados y mostrar errores en pantalla).


    📁 Archivos: leer y escribir con seguridad

    La forma profesional de trabajar con archivos es mediante el context manager with, que cierra el archivo automáticamente.

    Abrir y escribir (texto)

    # "w" = escribir (crea o sobrescribe)
    with open("salida.txt", "w", encoding="utf-8") as f:
        f.write("Hola, archivo 👋\n")
        f.write("Línea 2\n")
    

    Leer todo el contenido

    with open("salida.txt", "r", encoding="utf-8") as f:
        contenido = f.read()
    print(contenido)
    

    Leer línea a línea (memoria eficiente)

    with open("salida.txt", "r", encoding="utf-8") as f:
        for linea in f:
            print(">", linea.rstrip())
    

    Modos de apertura más usados

    ModoSignificadoNotas
    "r"LeerFalla si no existe
    "w"EscribirSobrescribe
    "a"AñadirEscribe al final
    "x"CrearFalla si existe
    "b"BinarioCombinar: "rb", "wb"
    "+"Lectura/Escriturap. ej. "r+"

    Binario (imágenes, PDFs…)

    # Copiar un archivo binario
    with open("foto.jpg", "rb") as src, open("copia.jpg", "wb") as dst:
        dst.write(src.read())
    

    Gestión de errores con archivos

    from pathlib import Path
    
    ruta = Path("datos.txt")
    try:
        with ruta.open("r", encoding="utf-8") as f:
            print(f.readline().strip())
    except FileNotFoundError:
        print("❌ Archivo no encontrado:", ruta)
    except PermissionError:
        print("❌ Permisos insuficientes para:", ruta)
    

    🌍 Codificaciones y saltos de línea

    Usa siempre encoding="utf-8" para evitar problemas con acentos/emoji.
    Controla los saltos de línea con newline= si trabajas datos multi-plataforma.

    # Escribir CSV compatible (Windows/macOS/Linux)
    import csv
    rows = [("id","nombre"), (1,"Javier"), (2,"Ana")]
    
    with open("usuarios.csv", "w", encoding="utf-8", newline="") as f:
        writer = csv.writer(f)
        writer.writerows(rows)
    

    💡 En Windows, el manejo de newline="" evita líneas en blanco extra en CSV.


    🔀 Redirección y captura de salida

    En la terminal (Bash, PowerShell)

    # Redirigir salida estándar a un archivo
    python mi_script.py > salida.log
    
    # Redirigir errores a otro archivo
    python mi_script.py 2> errores.log
    
    # Redirigir ambos (stdout y stderr)
    python mi_script.py > todo.log 2>&1
    
    # Encadenar por pipe
    python generar.py | python procesar.py
    

    Capturar salida en Python (pruebas / utilidades)

    import io
    from contextlib import redirect_stdout, redirect_stderr
    
    buffer_out = io.StringIO()
    buffer_err = io.StringIO()
    
    print("Inicio")
    
    with redirect_stdout(buffer_out):
        print("Esto va a stdout capturado")
    with redirect_stderr(buffer_err):
        import sys
        sys.stderr.write("Esto va a stderr capturado\\n")
    
    print("Fin")
    
    print("CAPTURA STDOUT:", buffer_out.getvalue().strip())
    print("CAPTURA STDERR:", buffer_err.getvalue().strip())
    

    💡 Útil para tests, generar informes o integrar scripts con otras herramientas.


    🧭 print() vs logging: ¿cuál usar y cuándo?

    Regla de oro: usa print() para interacción directa con el usuario; usa logging para diagnóstico y observabilidad.

    print()logging
    Mensajes al usuario / outputs sencillosRegistros del sistema, depuración, auditoría
    No tiene nivelesNiveles: DEBUG, INFO, WARNING, ERROR, CRITICAL
    Difícil de desactivar globalmenteConfiguración centralizada, filtros y handlers
    Siempre va a stdoutPuede ir a archivos, consola, syslog, HTTP, etc.

    Ejemplo de configuración básica de logging

    import logging
    
    logging.basicConfig(
        level=logging.INFO,                      # Nivel mínimo a registrar
        format="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S"
    )
    
    log = logging.getLogger("app")
    
    def conectar(db_url):
        log.debug("Iniciando conexión...")
        # ...
        log.info("Conectado a %s", db_url)
    
    def procesar(dato):
        if not dato:
            log.warning("Dato vacío, se omite")
            return
        # ...
        log.error("Error de ejemplo: %s", "detalle del error")
    
    conectar("postgresql://localhost")
    procesar("")
    

    Enviar logs a archivo y consola

    import logging
    
    logger = logging.getLogger("pipeline")
    logger.setLevel(logging.DEBUG)
    
    # Handler a archivo
    fh = logging.FileHandler("pipeline.log", encoding="utf-8")
    fh.setLevel(logging.INFO)
    
    # Handler a consola
    ch = logging.StreamHandler()
    ch.setLevel(logging.DEBUG)
    
    # Formato común
    fmt = logging.Formatter("%(levelname)s | %(message)s")
    fh.setFormatter(fmt)
    ch.setFormatter(fmt)
    
    logger.addHandler(fh)
    logger.addHandler(ch)
    
    logger.info("Inicio del pipeline")
    logger.debug("Detalle de depuración visible solo en consola")
    

    🧪 Patrones de prueba: entrada/salida

    Probar funciones que dependen de input()/print() es más fácil si separas lógica de I/O.
    Aun así, puedes simular entradas y capturar salidas con io.StringIO.

    import io, sys
    
    def saludo():
        nombre = input("Nombre: ")
        print(f"Hola, {nombre}")
    
    # Simular input y capturar output
    entrada = io.StringIO("Javier\n")
    salida = io.StringIO()
    sys.stdin, sys.stdout = entrada, salida  # ⚠️ manipulación global controlada
    try:
        saludo()
    finally:
        # Restablecer
        sys.stdin, sys.stdout = sys.__stdin__, sys.__stdout__
    
    print("CAPTURA:", salida.getvalue().strip())
    

    ✅ En frameworks como pytest, usarías los fixtures capsys/capfd para capturar salidas sin tocar sys manualmente.


    🧾 Checklist de I/O profesional

    • Usa with open(...) y encoding="utf-8".
    • Separa stdout y stderr para redirigir mejor.
    • Para datos tabulares, usa csv y newline="".
    • Captura salida en pruebas con redirect_stdout/StringIO.
    • Elige print() para UX, logging para registros.


    ⬆️ Volver al índice

    Nuestra puntuación
    ¡Haz clic para puntuar esta entrada!
    (Votos: 0 Promedio: 0)
    Scroll al inicio