Cerrábamos la lección anterior con TareaFácil calculando días restantes, porcentajes de avance y urgencias, pero con dos carencias muy visibles: la ficha se imprimía a razón de una línea por dato, ilegible, y todos los datos seguían escritos dentro del código. Para registrar la tarea de otro cliente había que abrir el editor.

Esta lección arregla las dos cosas, y con ello tu programa cruza una frontera importante: deja de ser algo que se edita para convertirse en algo que se usa. Un programa que se usa tiene dos puntos de contacto con el mundo: la entrada (los datos que recibe) y la salida (los resultados que muestra). En Python esos dos puntos se llaman input() y print().

Ya conoces print() desde el módulo 1, pero solo en su forma más simple. Aquí lo verás a fondo: varios argumentos, los parámetros sep y end, los caracteres de escape, y sobre todo las f-strings, la herramienta con la que se compone texto en el Python moderno y con la que por fin podrás mezclar palabras y variables en una sola línea, alinear columnas y mostrar decimales con la precisión que quieras. Después llegará input(), y con él un detalle que condiciona todo lo que viene: input() devuelve siempre texto, aunque el usuario teclee un número.

Contenido

  1. Entrada y salida: los dos puntos de contacto de un programa
  2. print() con varios argumentos
  3. Los parámetros sep y end
  4. Caracteres de escape: \n, \t y las comillas
  5. f-strings: interpolación de variables
  6. Expresiones dentro de una f-string
  7. Especificadores de formato: decimales y alineación
  8. Otras formas de formatear que verás en código ajeno
  9. input(): pedir datos por teclado
  10. El punto capital: input() siempre devuelve texto
  11. TareaFácil: la ficha se pide y se presenta
  12. Errores comunes y consejos
  13. Ejercicios
  14. Conclusión

  1. Entrada y salida: los dos puntos de contacto de un programa

Cualquier programa, desde el más simple hasta un sistema bancario, sigue el mismo esquema de tres fases:

flowchart LR
    A["ENTRADA<br/>datos que llegan"] --> B["PROCESO<br/>calculos y decisiones"]
    B --> C["SALIDA<br/>resultados que se muestran"]

Hasta ahora has trabajado en el centro: variables (02-01) y expresiones (02-02) son proceso puro. La entrada estaba fijada en el código y la salida era rudimentaria. Vamos a cubrir los dos extremos.

Los datos pueden entrar por muchas vías —teclado, ficheros, red, sensores— y salir por otras tantas. En este curso empezamos por la más directa: el teclado para entrar y la pantalla (concretamente, la terminal) para salir. Leer y escribir ficheros llegará en Guardar datos en archivos.

Una advertencia de fondo que conviene tener presente desde el primer día: todo lo que entra desde fuera es sospechoso. El usuario puede teclear un número donde esperabas un nombre, dejar el campo vacío o escribir «ALTA» en mayúsculas. Comprobar que los datos son correctos se llama validar, y es el tema de la próxima lección. Aquí nos ocupamos de recibirlos y mostrarlos.

  1. print() con varios argumentos

Hasta ahora has usado print() con un solo valor. Pero admite varios, separados por comas:

titulo = "Logotipo Panaderia Sole"
responsable = "Luis"

print("Titulo:", titulo)
print("Responsable:", responsable)

Salida:

Titulo: Logotipo Panaderia Sole
Responsable: Luis

Esto resuelve de golpe el problema que dejamos pendiente en la lección anterior: recuerda que "Titulo: " + titulo funcionaba solo con textos, y que "Dias: " + 3 daba TypeError. Con comas no hay problema, porque print() convierte cada valor a texto automáticamente:

dias_restantes = 7
porcentaje = 37.5
completada = False
fecha_entrega = None

print("Dias restantes:", dias_restantes)      # Dias restantes: 7
print("Porcentaje:", porcentaje)              # Porcentaje: 37.5
print("Completada:", completada)              # Completada: False
print("Entrega:", fecha_entrega)              # Entrega: None

Números, booleanos, None: print() los muestra todos sin protestar.

Hay dos detalles que observar. Primero: entre cada argumento aparece un espacio, puesto por Python, no por ti. Por eso "Titulo:" no lleva espacio final y aun así la salida se ve bien. Segundo: no hay límite de argumentos.

print("Tarea", 1, "de", 3, "->", 33.3, "%")
Tarea 1 de 3 -> 33.3 %

Fíjate en el resultado: el % aparece separado del número porque el espacio automático se pone entre todos los argumentos. Ese espacio automático es cómodo pero también rígido; el siguiente apartado explica cómo controlarlo.

Y un print() sin argumentos imprime una línea en blanco:

print()      # linea vacia

Es más limpio que print(""), que hace lo mismo.

  1. Los parámetros sep y end

print() admite dos parámetros con nombre que modifican su comportamiento.

sep cambia el separador que se pone entre los argumentos. Por defecto es un espacio.

print("alta", "media", "baja")                # alta media baja
print("alta", "media", "baja", sep=" / ")     # alta / media / baja
print("alta", "media", "baja", sep="")        # altamediabaja
print("2026", "08", "04", sep="-")            # 2026-08-04

Ese último ejemplo es el uso típico: componer una fecha o una ruta sin repetir el separador a mano.

end cambia lo que se imprime al final, después del último argumento. Por defecto es un salto de línea, "\n"; por eso cada print() empieza en una línea nueva.

print("Cargando", end="")
print(".", end="")
print(".", end="")
print(".", end="")
print(" listo")

Salida, toda en una sola línea:

Cargando... listo

Al poner end="" le dices a print() que no salte de línea, así que la siguiente instrucción continúa donde se quedó la anterior. Es el mecanismo de las barras de progreso y de cualquier salida que se construye por partes.

Combinando ambos:

print("Marta", "Luis", "Nuria", sep=", ", end=".\n")
Marta, Luis, Nuria.
Parámetro Valor por defecto Qué controla
sep " " (un espacio) Qué se pone entre los argumentos
end "\n" (salto de línea) Qué se pone después del último

Los parámetros con nombre como estos se llaman argumentos por palabra clave, y se estudian a fondo en Parámetros y retorno de valores. De momento basta con saber que se escriben nombre=valor y que van al final de la llamada.

  1. Caracteres de escape: \n, \t y las comillas

Dentro de una cadena de texto, la barra invertida \ tiene un significado especial: junto al carácter siguiente forma una secuencia de escape que representa algo que no se puede teclear directamente.

Escape Significado Uso típico
\n Salto de línea Varias líneas en un solo print
\t Tabulador Separar columnas
\" Comilla doble literal Comillas dentro de un texto entrecomillado con dobles
\' Comilla simple literal Ídem con simples
\\ Barra invertida literal Rutas de Windows

Saltos de línea. Un solo print puede producir varias líneas:

print("FICHA DE TAREA\n----------------\nCliente: Panaderia Sole")
FICHA DE TAREA
----------------
Cliente: Panaderia Sole

Tabuladores. \t avanza hasta la siguiente parada de tabulación, lo que da un efecto de columnas:

print("Marta\tcoordinadora")
print("Luis\tdiseno")
print("Nuria\tmaquetacion")
Marta	coordinadora
Luis	diseno
Nuria	maquetacion

Funciona, pero con una limitación importante: las paradas de tabulación son fijas (normalmente cada 8 caracteres), así que si un nombre es más largo que la parada, la columna se descuadra. Para alinear de verdad se usan los especificadores de anchura de las f-strings, que verás en el apartado 7.

Comillas dentro de texto. Hay tres formas de resolverlo:

# 1. Comillas distintas por dentro y por fuera
print("El cliente dijo: 'lo quiero para el viernes'")

# 2. Escapando las comillas
print("El cliente dijo: \"lo quiero para el viernes\"")

# 3. Comillas simples fuera, dobles dentro
print('El cliente dijo: "lo quiero para el viernes"')

La primera y la tercera son las más legibles; la segunda es útil cuando el texto contiene los dos tipos de comilla.

Barra invertida literal. Como \ inicia un escape, para escribir una barra hay que duplicarla:

print("C:\\Usuarios\\marta\\tareafacil")     # C:\Usuarios\marta\tareafacil

Existe también la cadena cruda, que desactiva los escapes: se marca con una r delante. Es muy práctica para rutas de Windows:

print(r"C:\Usuarios\marta\tareafacil")       # C:\Usuarios\marta\tareafacil

Y para textos largos de varias líneas, las comillas triples conservan el formato tal cual lo escribes:

print("""
=== TAREAFACIL ===
Gestor de tareas
Estudio Alba
""")

  1. f-strings: interpolación de variables

Llegamos a la herramienta central de esta lección. Una f-string (cadena formateada) es una cadena precedida por la letra f en la que puedes insertar variables entre llaves {}.

responsable = "Luis"
dias_restantes = 7

print(f"La tarea es de {responsable} y quedan {dias_restantes} dias.")
La tarea es de Luis y quedan 7 dias.

Compara las tres formas de hacer lo mismo:

Forma Código Problema
Concatenación "La tarea es de " + responsable No admite números sin convertirlos
Argumentos de print print("La tarea es de", responsable) Espacios automáticos difíciles de controlar
f-string f"La tarea es de {responsable}" Ninguno: se lee como el resultado

La ventaja decisiva de la f-string es que el código se parece al resultado. Ves la frase completa y, dentro, en su sitio exacto, el hueco que ocupará el dato. Y funciona con cualquier tipo, sin conversiones:

titulo = "Logotipo Panaderia Sole"
horas = 9.5
completada = False
fecha = None

print(f"Tarea: {titulo}")             # Tarea: Logotipo Panaderia Sole
print(f"Horas: {horas}")              # Horas: 9.5
print(f"Hecha: {completada}")         # Hecha: False
print(f"Entrega: {fecha}")            # Entrega: None

La f va pegada a la comilla de apertura, y puede ir con comillas simples, dobles o triples. Si olvidas la f, no hay error: se imprimen las llaves literalmente, que es un despiste muy común.

print("Quedan {dias_restantes} dias")     # Quedan {dias_restantes} dias  <- falta la f
print(f"Quedan {dias_restantes} dias")    # Quedan 7 dias

Si necesitas una llave literal dentro de una f-string, dupliícala: {{ produce {.

  1. Expresiones dentro de una f-string

Dentro de las llaves no solo caben variables: cabe cualquier expresión de las que aprendiste en la lección anterior.

horas_dedicadas = 9
horas_estimadas = 24
dia_actual = 12
dia_entrega = 19
prioridad = "alta"
completada = False

print(f"Avance: {horas_dedicadas / horas_estimadas * 100} %")
print(f"Quedan {dia_entrega - dia_actual} dias")
print(f"Horas por hacer: {horas_estimadas - horas_dedicadas}")
print(f"Urgente: {prioridad == 'alta' and not completada}")
Avance: 37.5 %
Quedan 7 dias
Horas por hacer: 15
Urgente: True

Fíjate en la última línea: dentro de las llaves hay una expresión lógica completa, y en la f-string se han usado comillas simples para 'alta' porque las dobles ya están ocupadas por la cadena exterior. Mezclar los dos tipos de comilla es la forma de evitar el conflicto.

Ahora bien, un consejo de estilo: que puedas meter expresiones complejas no significa que debas. Esta línea es correcta pero ilegible:

print(f"{(horas_dedicadas / horas_estimadas * 100 > 60) and (dia_entrega - dia_actual < 5)}")

Es mucho mejor calcular antes, con un nombre que explique qué es, y limitar la f-string a mostrar:

porcentaje_avance = horas_dedicadas / horas_estimadas * 100
dias_restantes = dia_entrega - dia_actual
va_justo = porcentaje_avance > 60 and dias_restantes < 5

print(f"Va justo de plazo: {va_justo}")

La regla práctica: dentro de una f-string, expresiones cortas y evidentes; el resto, en una variable con nombre.

Un truco útil para depurar: si pones un = después de la expresión, la f-string muestra también el código que la generó.

horas_dedicadas = 9
print(f"{horas_dedicadas=}")          # horas_dedicadas=9

Es comodísimo cuando estás buscando por qué un valor no es el que esperabas.

  1. Especificadores de formato: decimales y alineación

Dentro de las llaves puedes añadir, tras dos puntos, un especificador de formato que controla cómo se presenta el valor. La sintaxis general es {valor:formato}.

Controlar los decimales

El problema es evidente en cuanto calculas un porcentaje:

porcentaje = 37.333333333333336
print(f"Avance: {porcentaje} %")            # Avance: 37.333333333333336 %
print(f"Avance: {porcentaje:.2f} %")        # Avance: 37.33 %
print(f"Avance: {porcentaje:.1f} %")        # Avance: 37.3 %
print(f"Avance: {porcentaje:.0f} %")        # Avance: 37 %

.2f significa «formato de coma flotante con 2 decimales». Redondea, no trunca: 37.336 con .2f da 37.34.

Es el especificador que más usarás. Cualquier cantidad calculada con / que vaya a mostrarse a una persona debería llevarlo.

Alinear en columnas

Aquí es donde las f-strings superan definitivamente al tabulador \t. Puedes fijar una anchura mínima y una alineación:

Especificador Significado Ejemplo con "Luis"
{texto:<10} Alinea a la izquierda en 10 caracteres Luis______
{texto:>10} Alinea a la derecha en 10 caracteres ______Luis
{texto:^10} Centra en 10 caracteres ___Luis___
{texto:<10} con relleno {texto:.<10} rellena con puntos Luis......

(Los guiones bajos representan espacios.)

Veámoslo componiendo una tabla del equipo de Estudio Alba:

print(f"{'RESPONSABLE':<12}{'TAREAS':>8}{'HORAS':>8}")
print("-" * 28)
print(f"{'Marta':<12}{3:>8}{12.5:>8}")
print(f"{'Luis':<12}{5:>8}{27.0:>8}")
print(f"{'Nuria':<12}{2:>8}{9.25:>8}")
RESPONSABLE   TAREAS   HORAS
----------------------------
Marta              3    12.5
Luis               5    27.0
Nuria              2    9.25

El texto se alinea a la izquierda (<) porque así se leen las palabras; los números a la derecha (>) porque así se alinean las unidades, las decenas y las centenas. Es la convención de cualquier tabla bien hecha.

Y se pueden combinar anchura y decimales, poniendo la anchura primero y la precisión después:

print(f"{'Marta':<12}{12.5:>8.2f}")
print(f"{'Luis':<12}{27.0:>8.2f}")
print(f"{'Nuria':<12}{9.25:>8.2f}")
Marta          12.50
Luis           27.00
Nuria           9.25

Ahora sí: columna perfecta, con dos decimales en todos los casos.

Especificador Qué hace
{x:.2f} 2 decimales
{x:>8} Anchura 8, alineado a la derecha
{x:<15} Anchura 15, alineado a la izquierda
{x:^20} Anchura 20, centrado
{x:>10.2f} Anchura 10, a la derecha, 2 decimales
{x:,} Separador de miles: 1250000 → 1,250,000
{x:.1%} Como porcentaje: 0.375 → 37.5%

Ese último merece una nota: {0.375:.1%} multiplica por 100 y añade el símbolo. Si tu valor ya está en escala 0-100, usa .1f y escribe el % tú.

  1. Otras formas de formatear que verás en código ajeno

Las f-strings existen desde Python 3.6 y son la forma recomendada hoy. Pero encontrarás código —tutoriales antiguos, proyectos heredados— escrito con las dos formas anteriores, y conviene reconocerlas.

El método .format(), de Python 3.0 en adelante:

responsable = "Luis"
dias = 7

print("La tarea es de {} y quedan {} dias.".format(responsable, dias))
print("La tarea es de {0} y quedan {1} dias.".format(responsable, dias))
print("Avance: {:.2f} %".format(37.333))

Los huecos {} se rellenan en orden con los argumentos de .format(). Los especificadores tras los dos puntos son los mismos que en las f-strings, así que lo aprendido en el apartado anterior te sirve igual.

El operador %, heredado del lenguaje C y todavía presente en mucho código antiguo:

print("La tarea es de %s y quedan %d dias." % (responsable, dias))
print("Avance: %.2f %%" % 37.333)

Aquí %s es un hueco para texto, %d para entero y %.2f para decimal con dos cifras. Es el más críptico de los tres y el más propenso a errores.

Forma Aspecto Cuándo usarla
f-string f"Hola {nombre}" Siempre, en código nuevo
.format() "Hola {}".format(nombre) Solo si mantienes código antiguo
% "Hola %s" % nombre Nunca en código nuevo; reconocerlo basta

Quédate con esto: escribe f-strings, y si te topas con las otras dos, ya sabes qué hacen.

  1. input(): pedir datos por teclado

input() es la función que detiene el programa y espera a que el usuario teclee algo y pulse Intro.

responsable = input()
print(responsable)

Ese programa se queda esperando sin decir nada, lo cual es una pésima experiencia de uso. Por eso input() admite un argumento: el mensaje de indicación o prompt, que se muestra antes de esperar.

responsable = input("Responsable de la tarea: ")
print(f"Tarea asignada a {responsable}")

Ejecución (lo que teclea el usuario va subrayado por el cursor, aquí lo marcamos aparte):

Responsable de la tarea: Nuria
Tarea asignada a Nuria

El funcionamiento paso a paso:

flowchart TD
    A["El programa llega a input()"] --> B["Muestra el mensaje del prompt"]
    B --> C["Se DETIENE y espera"]
    C --> D["El usuario teclea y pulsa Intro"]
    D --> E["input() devuelve lo tecleado<br/>como texto"]
    E --> F["Ese texto se asigna a la variable"]

Tres detalles de uso que marcan la diferencia:

1. Termina el prompt con espacio o dos puntos y espacio. Sin él, lo que teclee el usuario aparecerá pegado al mensaje:

nombre = input("Responsable:")       # Responsable:Nuria   <- feo
nombre = input("Responsable: ")      # Responsable: Nuria  <- correcto

2. Di exactamente qué esperas. Un prompt vago genera datos inservibles:

prioridad = input("Prioridad: ")                        # el usuario no sabe que poner
prioridad = input("Prioridad (alta/media/baja): ")      # mucho mejor

3. El resultado hay que guardarlo. Escribir input("Nombre: ") sin asignar a nada pide el dato y lo tira. Es un despiste habitual.

Y una consecuencia que se nota al ejecutar: input() bloquea el programa. Nada más ocurre hasta que el usuario pulsa Intro. Si tu programa parece «colgado», comprueba si está esperando una entrada.

  1. El punto capital: input() siempre devuelve texto

Aquí está la idea más importante de la lección, y conviene que la leas dos veces:

input() devuelve SIEMPRE un valor de tipo str, sin excepciones, aunque el usuario teclee un número.

Compruébalo:

dias = input("Dias estimados: ")

print(dias)          # 3
print(type(dias))    # <class 'str'>   <- NO es int

El usuario ha tecleado 3, en pantalla se ve 3, pero lo que hay guardado es el texto "3", no el número 3. Y eso tiene consecuencias inmediatas y desconcertantes:

dias = input("Dias estimados: ")     # el usuario teclea 3

print(dias * 2)      # 33     <- repite el texto, no multiplica!

"3" * 2 es repetición de cadena, que ya viste en la lección anterior: produce "33". No es un fallo de Python; es que estás multiplicando texto.

Y si intentas aritmética de verdad, el programa se detiene:

dias = input("Dias estimados: ")     # el usuario teclea 3

print(dias + 1)
TypeError: can only concatenate str (not "int") to str

Es el mismo TypeError de la lección anterior, visto ahora desde el otro lado. Resumamos qué ocurre según lo que se intente:

Operación con dias = input() (usuario teclea 3) Resultado
print(dias) Muestra 3 — parece un número
type(dias) <class 'str'> — no lo es
dias + 1 TypeError
dias * 2 "33" (repetición, no multiplicación)
dias > 2 TypeError — no se puede comparar texto con número
f"Dias: {dias}" Dias: 3 — funciona, porque solo se muestra

Fíjate en la última fila: mostrar el dato funciona perfectamente. El problema aparece solo cuando quieres calcular con él.

Por eso, en la aplicación de esta lección, TareaFácil pedirá únicamente datos que son texto por naturaleza —título, responsable, prioridad— y no pedirá los días estimados ni las horas. En cuanto haga falta un número, necesitaremos convertirlo, y esa conversión, junto con lo que pasa si el usuario teclea «tres» en lugar de «3», es exactamente el contenido de Conversión de tipos y validación.

Dejamos, pues, dos cabos sueltos anotados:

  • input() devuelve texto y a veces necesitamos números.
  • El usuario puede escribir "ALTA", " alta " o "urgente", y ninguno de los tres coincide con "alta" (aquel descubrimiento de la prueba de escritorio de 01-05).

Los dos se atan en la próxima lección.

  1. TareaFácil: la ficha se pide y se presenta

Versión 0.4 de tareafacil.py. El programa pide por teclado los tres datos de texto de la tarea y muestra una ficha alineada en columnas con f-strings. Los datos numéricos siguen en el código, a la espera de saber convertirlos.

# tareafacil.py - Estudio Alba
# Version 0.4: los datos de texto se piden por teclado
#              y la ficha se presenta con f-strings

NOMBRE_APP = "TareaFacil"
VERSION = "0.4"
ESTUDIO = "Estudio Alba"
ANCHO = 46
HORAS_POR_JORNADA = 8

# --- Cabecera ---
print("=" * ANCHO)
print(f"{NOMBRE_APP + ' v' + VERSION:^{ANCHO}}")
print(f"{'Gestor de tareas de ' + ESTUDIO:^{ANCHO}}")
print("=" * ANCHO)
print()

# --- ENTRADA: datos que teclea el usuario ---
print("Introduce los datos de la tarea:")
print()

titulo = input("  Titulo                      : ")
descripcion = input("  Descripcion                 : ")
responsable = input("  Responsable (Marta/Luis/Nuria): ")
prioridad = input("  Prioridad (alta/media/baja) : ")

# --- Datos que todavia no podemos pedir (son numeros) ---
dia_actual = 12
dia_entrega = 19
horas_estimadas = 24
horas_dedicadas = 9
completada = False

# --- PROCESO: calculos con los datos ---
dias_restantes = dia_entrega - dia_actual
porcentaje_avance = horas_dedicadas / horas_estimadas * 100
horas_restantes = horas_estimadas - horas_dedicadas
jornadas_restantes = horas_restantes / HORAS_POR_JORNADA
es_urgente = prioridad == "alta" and not completada

# --- SALIDA: ficha alineada ---
print()
print("=" * ANCHO)
print(f"{'FICHA DE TAREA':^{ANCHO}}")
print("=" * ANCHO)
print(f"{'Titulo':<16}{titulo:>{ANCHO - 16}}")
print(f"{'Responsable':<16}{responsable:>{ANCHO - 16}}")
print(f"{'Prioridad':<16}{prioridad:>{ANCHO - 16}}")
print(f"{'Completada':<16}{str(completada):>{ANCHO - 16}}")
print("-" * ANCHO)
print(f"{'Dias restantes':<16}{dias_restantes:>{ANCHO - 16}}")
print(f"{'Horas hechas':<16}{horas_dedicadas:>{ANCHO - 16}.1f}")
print(f"{'Horas totales':<16}{horas_estimadas:>{ANCHO - 16}.1f}")
print(f"{'Avance':<16}{porcentaje_avance:>{ANCHO - 18}.1f} %")
print(f"{'Jornadas rest.':<16}{jornadas_restantes:>{ANCHO - 16}.2f}")
print("-" * ANCHO)
print(f"{'Urgente':<16}{str(es_urgente):>{ANCHO - 16}}")
print("=" * ANCHO)
print()
print(f"Descripcion: {descripcion}")

Una ejecución completa, con Marta registrando el encargo del cliente Vidal:

==============================================
                TareaFacil v0.4
        Gestor de tareas de Estudio Alba
==============================================

Introduce los datos de la tarea:

  Titulo                      : Tarjetas de visita Vidal
  Descripcion                 : 300 uds, doble cara, papel reciclado
  Responsable (Marta/Luis/Nuria): Nuria
  Prioridad (alta/media/baja) : alta

==============================================
                FICHA DE TAREA
==============================================
Titulo                Tarjetas de visita Vidal
Responsable                              Nuria
Prioridad                                 alta
Completada                               False
----------------------------------------------
Dias restantes                               7
Horas hechas                               9.0
Horas totales                             24.0
Avance                                  37.5 %
Jornadas rest.                            1.88
----------------------------------------------
Urgente                                   True
==============================================

Descripcion: 300 uds, doble cara, papel reciclado

Repasemos las técnicas empleadas, porque el ejemplo condensa toda la lección:

  • "=" * ANCHO dibuja los separadores. Es la repetición de cadenas de la lección anterior, aquí con un uso muy práctico.
  • {texto:^{ANCHO}} centra el título en el ancho total. Fíjate en el detalle avanzado: la anchura no está escrita a mano, es otra variable entre llaves. Así, cambiando ANCHO en la primera línea, toda la ficha se reajusta.
  • {'Titulo':<16} reserva 16 caracteres para la etiqueta, alineada a la izquierda.
  • {titulo:>{ANCHO - 16}} ocupa el resto de la línea con el valor alineado a la derecha. Dentro de las llaves de anchura hay una expresión, ANCHO - 16, perfectamente válida.
  • {porcentaje_avance:>{ANCHO - 18}.1f} % combina anchura, alineación y un decimal; el - 18 en vez de - 16 deja hueco para los dos caracteres del % que van detrás, de modo que la línea sigue midiendo exactamente ANCHO.
  • str(completada) convierte el booleano a texto. Es necesario porque los especificadores de alineación < y > funcionan de forma distinta con booleanos que con cadenas; convirtiéndolo primero, se alinea como cualquier otro texto. La función str() es, precisamente, lo primero que verás en la próxima lección.

Lo que sigue sin funcionar

Prueba esta ejecución y observa el resultado:

  Responsable (Marta/Luis/Nuria): NURIA
  Prioridad (alta/media/baja) : ALTA

La ficha se genera igual de bonita, pero abajo pone Urgente False. La comparación prioridad == "alta" ha fallado porque el usuario escribió en mayúsculas. Y si escribe urgentisima, o deja el campo en blanco pulsando Intro, el programa tampoco protesta: guarda la basura y sigue.

Ese es exactamente el trabajo pendiente.

Errores Comunes y Consejos

Olvidar la f de la f-string. print("Quedan {dias} dias") imprime las llaves tal cual. No da error, así que hay que verlo en la salida. Si ves llaves en pantalla, falta la f.

Usar comillas dobles dentro de una f-string delimitada por dobles. f"Es {x == "alta"}" rompe la cadena. Usa comillas simples dentro: f"Es {x == 'alta'}".

Confundir .2f con «dos dígitos». .2f son dos decimales, no dos cifras en total. Para anchura total se usa el número antes del punto: {x:8.2f}.

Alinear números a la izquierda. Queda desalineado y cuesta comparar magnitudes. Texto a la izquierda (<), números a la derecha (>).

Confiar en \t para hacer tablas. Funciona mientras todos los valores midan menos que la parada de tabulación; en cuanto uno se pasa, la columna se descuadra. Usa anchuras explícitas.

No asignar el resultado de input(). input("Nombre: ") sin variable = delante pide el dato y lo descarta.

Prompt sin espacio final. input("Nombre:") hace que lo tecleado se pegue al mensaje. Deja siempre un espacio.

Dar por hecho que input() devuelve un número. Es el error que define esta lección: siempre devuelve str. Si vas a calcular, tendrás que convertir.

Prompts que no explican las opciones. Si solo se admiten tres prioridades, escríbelas en el prompt. El coste de un prompt claro es cero y ahorra la mitad de las entradas erróneas.

Consejo: separa entrada, proceso y salida. Mira la estructura del programa de esta lección: primero todos los input(), después todos los cálculos, y al final toda la presentación. Es más fácil de leer, de probar y de modificar que si están entremezclados. Esta separación es un principio de diseño que se mantiene en programas de cualquier tamaño.

Consejo: define el ancho como constante. ANCHO = 46 en lugar de repetir 46 en quince líneas. Cambiar el diseño de la ficha pasa a ser cuestión de una línea.

Consejo: prueba con datos incómodos. Ejecuta tu programa y teclea un título larguísimo, o pulsa Intro sin escribir nada. La ficha se descuadrará o quedará vacía. Anota lo que has visto: eso es lo que hay que validar.

Ejercicios

Ejercicio 1: Predecir la salida

Escribe exactamente qué imprime cada bloque, prestando atención a espacios y saltos de línea.

# a)
print("Marta", "Luis", "Nuria", sep=" | ")

# b)
print("Tarea", end=" -> ")
print("completada")

# c)
horas = 7.456
print(f"{horas:.2f}")
print(f"{horas:.0f}")

# d)
nombre = "Luis"
print(f"[{nombre:<10}]")
print(f"[{nombre:>10}]")
print(f"[{nombre:^10}]")

# e)
print("Linea 1\n\tLinea 2 tabulada")

# f)
dias = 5
print("Quedan {dias} dias")
print(f"Quedan {dias} dias")

# g)
print(f"{'Total':<8}{1250:>10,}")

Ejercicio 2: Ficha del equipo de Estudio Alba

Escribe un programa resumen_equipo.py que muestre esta tabla usando solo f-strings (nada de \t), con estos datos ya escritos en variables:

Persona Tareas pendientes Horas dedicadas Porcentaje de carga
Marta 3 12.5 0.25
Luis 5 27.0 0.45
Nuria 2 9.25 0.30

Requisitos:

  • Cabecera centrada en un ancho de 44 caracteres, con líneas de = arriba y abajo.
  • Nombres alineados a la izquierda; números a la derecha.
  • Horas con un decimal; el porcentaje de carga mostrado como porcentaje con un decimal (recuerda {x:.1%}).
  • El ancho total debe estar en una constante y usarse en todas las líneas.

Ejercicio 3: Registro interactivo de tarea

Escribe registro_tarea.py que:

  1. Muestre una cabecera de bienvenida.
  2. Pida por teclado, con prompts claros: título, cliente, responsable y prioridad.
  3. Muestre una ficha con los cuatro datos alineados en dos columnas.
  4. Al final, muestre en una sola línea, usando una f-string con una expresión dentro, si la tarea es de prioridad alta.
  5. Imprima el type() de la variable prioridad y explica en un comentario qué significa el resultado.

Soluciones

Solución 1.

a) Marta | Luis | Nuria — el sep sustituye el espacio por " | ".

b)

Tarea -> completada

Una sola línea: el primer print no salta porque end=" -> ".

c)

7.46
7

.2f redondea a dos decimales (7.456 → 7.46) y .0f a cero decimales (7.456 → 7).

d)

[Luis      ]
[      Luis]
[   Luis   ]

Diez caracteres de anchura en los tres casos; cambia dónde se coloca el texto. Al centrar con anchura impar sobrante, el hueco extra va a la derecha.

e)

Linea 1
	Linea 2 tabulada

\n salta de línea y \t mete un tabulador al principio de la segunda.

f)

Quedan {dias} dias
Quedan 5 dias

Sin la f, las llaves son texto literal. Es el despiste más común.

g) Total 1,250 — Total ocupa 8 caracteres a la izquierda, y 1250 se muestra con separador de miles en 10 caracteres a la derecha.

Solución 2.

# resumen_equipo.py - Estudio Alba

ANCHO = 44

marta_tareas = 3
marta_horas = 12.5
marta_carga = 0.25

luis_tareas = 5
luis_horas = 27.0
luis_carga = 0.45

nuria_tareas = 2
nuria_horas = 9.25
nuria_carga = 0.30

print("=" * ANCHO)
print(f"{'RESUMEN DEL EQUIPO - Estudio Alba':^{ANCHO}}")
print("=" * ANCHO)
print(f"{'PERSONA':<14}{'TAREAS':>8}{'HORAS':>11}{'CARGA':>11}")
print("-" * ANCHO)
print(f"{'Marta':<14}{marta_tareas:>8}{marta_horas:>11.1f}{marta_carga:>11.1%}")
print(f"{'Luis':<14}{luis_tareas:>8}{luis_horas:>11.1f}{luis_carga:>11.1%}")
print(f"{'Nuria':<14}{nuria_tareas:>8}{nuria_horas:>11.1f}{nuria_carga:>11.1%}")
print("=" * ANCHO)

Salida:

============================================
     RESUMEN DEL EQUIPO - Estudio Alba
============================================
PERSONA         TAREAS      HORAS      CARGA
--------------------------------------------
Marta                3       12.5      25.0%
Luis                 5       27.0      45.0%
Nuria                2        9.2      30.0%
============================================

Fíjate en las anchuras elegidas: 14 + 8 + 11 + 11 = 44, exactamente ANCHO. Cuando las columnas suman el ancho total, las líneas de = y - encajan con la tabla y el resultado parece hecho a propósito, que es justo lo que buscamos.

Observa también que 9.25 con .1f se muestra como 9.2 y no como 9.3: ante un empate exacto, Python redondea al dígito par más cercano (el llamado redondeo bancario). No es un error, pero conviene saberlo cuando presentes cifras a un cliente.

Solución 3.

# registro_tarea.py - Estudio Alba

ANCHO = 44

print("=" * ANCHO)
print(f"{'REGISTRO DE NUEVA TAREA':^{ANCHO}}")
print(f"{'Estudio Alba':^{ANCHO}}")
print("=" * ANCHO)
print()

titulo = input("Titulo de la tarea            : ")
cliente = input("Cliente                       : ")
responsable = input("Responsable (Marta/Luis/Nuria): ")
prioridad = input("Prioridad (alta/media/baja)   : ")

print()
print("-" * ANCHO)
print(f"{'FICHA':^{ANCHO}}")
print("-" * ANCHO)
print(f"{'Titulo':<14}{titulo:>{ANCHO - 14}}")
print(f"{'Cliente':<14}{cliente:>{ANCHO - 14}}")
print(f"{'Responsable':<14}{responsable:>{ANCHO - 14}}")
print(f"{'Prioridad':<14}{prioridad:>{ANCHO - 14}}")
print("-" * ANCHO)

print(f"Es de prioridad alta: {prioridad == 'alta'}")

# <class 'str'>: input() devuelve SIEMPRE texto, aunque el usuario
# teclee un numero. Por eso la comparacion de arriba solo funciona
# si escribe exactamente "alta" en minusculas.
print(type(prioridad))

Ejemplo de ejecución:

============================================
          REGISTRO DE NUEVA TAREA
                Estudio Alba
============================================

Titulo de la tarea            : Cartel feria del libro
Cliente                       : Asociacion de libreros
Responsable (Marta/Luis/Nuria): Nuria
Prioridad (alta/media/baja)   : media

--------------------------------------------
                   FICHA
--------------------------------------------
Titulo                Cartel feria del libro
Cliente               Asociacion de libreros
Responsable                            Nuria
Prioridad                              media
--------------------------------------------
Es de prioridad alta: False
<class 'str'>

Prueba a ejecutarlo de nuevo escribiendo ALTA en la prioridad: la ficha saldrá igual de correcta, pero Es de prioridad alta seguirá diciendo False. Ese es el problema que resolvemos a continuación.

Conclusión

Tu programa ya habla con el mundo. Sabes que print() acepta varios argumentos separados por comas —convirtiendo cada uno a texto automáticamente— y que sus parámetros sep y end controlan qué se pone entre los valores y qué se pone al final. Manejas los caracteres de escape \n, \t, \" y \\, y sabes resolver las comillas dentro de un texto de tres formas distintas.

Sobre todo, dominas las f-strings: interpolar variables y expresiones entre llaves, redondear decimales con .2f, y alinear columnas con <, > y ^ para producir tablas legibles sin depender del tabulador. Reconoces además .format() y el antiguo % cuando los encuentres en código ajeno, aunque escribas siempre f-strings.

Y conoces input(): cómo detiene el programa, cómo se le pone un mensaje útil y —el punto que gobierna la próxima lección— que devuelve siempre un str, aunque el usuario teclee un número.

TareaFácil está en su versión 0.4 y ya se parece a una herramienta: Marta lo ejecuta, teclea el título, la descripción, el responsable y la prioridad del encargo, y obtiene una ficha alineada con los cálculos de plazo y avance. Nadie tiene que abrir el editor para registrar una tarea nueva.

Pero hemos dejado dos cabos sueltos bien visibles. El primero: los datos numéricos —días estimados, horas dedicadas— siguen escritos en el código, porque lo que llega de input() es texto y "3" + 1 da TypeError. El segundo: el programa se traga cualquier cosa que le teclee el usuario. Si Marta escribe ALTA, la comparación falla; si escribe urgentisima, se guarda tal cual; si pulsa Intro sin escribir, la tarea se queda sin título.

Los dos son el mismo problema visto de dos maneras: los datos que vienen de fuera no son de fiar. En Conversión de tipos y validación aprenderás a convertirlos al tipo correcto con int(), float() y str(), a sanearlos con .strip() y .lower() —lo que por fin hará que "ALTA" valga tanto como "alta", el cabo que dejamos suelto en la lección 01-05— y a comprobar que son válidos antes de usarlos. Con eso cerraremos el módulo 2 y TareaFácil será, por primera vez, un programa robusto.

Fundamentos de la Programación

Módulo 1: Introducción a la Programación

Módulo 2: Conceptos Básicos

Módulo 3: Estructuras de Control

Módulo 4: Funciones y Procedimientos

Módulo 5: Estructuras de Datos

Módulo 6: Algoritmos Básicos

Módulo 7: Objetos y Organización del Código

Módulo 8: Buenas Prácticas y Herramientas

Módulo 9: Proyecto Final y Cierre del Curso

© Copyright 2026. Todos los derechos reservados