Objetivo del mini-reto
Vas a construir un conversor de unidades por consola que aplique reglas (qué conversiones están permitidas) y entregue resultados con precisión controlada (redondeo consistente). La idea es que tu programa no solo “haga cuentas”, sino que también se comporte como una herramienta confiable: valida la solicitud, rechaza combinaciones inválidas y formatea la salida.
Qué significa “reglas” en un conversor
Un conversor real no permite cualquier combinación. Por ejemplo, convertir metros a kilogramos no tiene sentido. Aquí las “reglas” se implementan como un catálogo de conversiones válidas, agrupadas por categoría (longitud, masa, temperatura, etc.).
Reglas mínimas recomendadas
- Solo se puede convertir dentro de la misma categoría (longitud con longitud, masa con masa).
- Si una unidad no existe en el catálogo, se rechaza.
- Si la conversión no está definida, se rechaza (aunque ambas unidades existan).
- La salida debe respetar una cantidad de decimales configurable.
Qué significa “precisión” (y por qué importa)
En conversiones, especialmente con decimales, es común obtener resultados como 1.9999999997 por cómo se representan los números en la computadora. Para que el usuario vea un resultado “humano”, se define una regla de redondeo: por ejemplo, mostrar siempre 2 o 3 decimales.
Decisiones de precisión
- Decimales fijos: siempre mostrar N decimales (útil para consistencia).
- Decimales configurables: el usuario elige N (útil para flexibilidad).
- Redondeo: usar
round(valor, decimales)y/o formateo con f-strings.
Diseño del conversor: enfoque práctico
Para que sea fácil de ampliar, separa el problema en dos partes: (1) un catálogo de unidades y reglas, (2) una función que resuelva la conversión y aplique precisión.
Catálogo por categorías (con factores)
Para unidades lineales (longitud, masa), una forma simple es definir un “factor” respecto a una unidad base. Ejemplo: en longitud, base = metro. Entonces km vale 1000 metros, cm vale 0.01 metros, etc. Convertir se vuelve: valor_en_base = valor * factor_origen y luego valor_destino = valor_en_base / factor_destino.
Continúa en nuestra aplicación.
Podrás escuchar el audiolibro con la pantalla apagada, recibir un certificado gratuito para este curso y además tener acceso a otros 5.000 cursos online gratuitos.
O continúa leyendo más abajo...Descargar la aplicación
UNIDADES = { "longitud": { "m": 1.0, "km": 1000.0, "cm": 0.01, "mm": 0.001 }, "masa": { "kg": 1.0, "g": 0.001, "lb": 0.45359237 } }Para temperatura, no alcanza con factores porque hay desplazamientos (C↔F). Ahí conviene definir reglas como funciones específicas.
def c_a_f(c): return (c * 9/5) + 32def f_a_c(f): return (f - 32) * 5/9Guía paso a paso (implementación)
Paso 1: define las reglas de conversión
Combina dos enfoques: factores para categorías “multiplicativas” y funciones para casos especiales como temperatura.
UNIDADES = { "longitud": {"m": 1.0, "km": 1000.0, "cm": 0.01, "mm": 0.001}, "masa": {"kg": 1.0, "g": 0.001, "lb": 0.45359237}}TEMPERATURA = { ("c", "f"): lambda c: (c * 9/5) + 32, ("f", "c"): lambda f: (f - 32) * 5/9, ("c", "k"): lambda c: c + 273.15, ("k", "c"): lambda k: k - 273.15}Nota: usa claves en minúsculas para simplificar la validación. Si el usuario escribe KM, lo pasas a km.
Paso 2: crea una función para detectar la categoría
Necesitas saber si ambas unidades pertenecen a la misma categoría (longitud o masa) para permitir la conversión por factores.
def categoria_de(unidad): for categoria, mapa in UNIDADES.items(): if unidad in mapa: return categoria return NonePaso 3: implementa la conversión con reglas
La función debe: validar unidades, decidir si usa factores o funciones especiales, y rechazar lo inválido con un mensaje claro.
def convertir(valor, origen, destino): origen = origen.lower().strip() destino = destino.lower().strip() # 1) Reglas especiales: temperatura if (origen, destino) in TEMPERATURA: return TEMPERATURA[(origen, destino)](valor) # 2) Reglas por categoría (factores) cat_origen = categoria_de(origen) cat_destino = categoria_de(destino) if cat_origen is None or cat_destino is None: raise ValueError("Unidad desconocida (no está en el catálogo)") if cat_origen != cat_destino: raise ValueError("Conversión inválida: unidades de categorías distintas") factor_origen = UNIDADES[cat_origen][origen] factor_destino = UNIDADES[cat_origen][destino] valor_base = valor * factor_origen return valor_base / factor_destinoPaso 4: aplica precisión y formatea la salida
Decide cuántos decimales mostrar. Puedes pedirlos al usuario o fijarlos. Aquí se muestra un ejemplo configurable.
def formatear_resultado(valor, decimales): redondeado = round(valor, decimales) return f"{redondeado:.{decimales}f}"Esto asegura decimales fijos. Por ejemplo, con 2 decimales, 3 se muestra como 3.00.
Paso 5: arma el flujo por consola (entrada → reglas → salida)
Este flujo guía al usuario y muestra errores sin “romper” la experiencia. Mantén el intercambio simple: valor, unidad origen, unidad destino, decimales.
def main(): print("Conversor de unidades") print("Ejemplos: 1500 m a km | 2.5 kg a lb | 100 c a f") valor_txt = input("Valor: ") origen = input("Unidad origen: ") destino = input("Unidad destino: ") dec_txt = input("Decimales (por ejemplo 2): ") try: valor = float(valor_txt) decimales = int(dec_txt) if decimales < 0 or decimales > 10: raise ValueError("Decimales fuera de rango (0 a 10)") resultado = convertir(valor, origen, destino) salida = formatear_resultado(resultado, decimales) print(f"Resultado: {salida} {destino.lower().strip()}") except ValueError as e: print(f"Error: {e}")Mini-reto: requisitos exactos a cumplir
Parte A (obligatoria): conversiones por factores
- Soporta al menos longitud:
mm,cm,m,km. - Soporta al menos masa:
g,kg,lb. - Rechaza conversiones entre categorías (ej.:
makg). - Rechaza unidades desconocidas.
- Permite elegir decimales (0 a 10).
Parte B (obligatoria): reglas especiales de temperatura
- Soporta al menos
c↔fyc↔k. - Estas conversiones deben funcionar aunque no estén en el mapa de factores.
Parte C (precisión): salida consistente
- Muestra el resultado con el número de decimales indicado.
- Evita mostrar “ruido” de coma flotante (usa
roundy formateo).
Casos de prueba rápidos (para verificar reglas y precisión)
- Longitud:
1500 m → kmcon 2 decimales debe dar1.50. - Longitud:
1 km → mmcon 0 decimales debe dar1000000. - Masa:
2.5 kg → lbcon 3 decimales debe dar aproximadamente5.512. - Temperatura:
100 c → fcon 1 decimal debe dar212.0. - Regla de categorías:
10 m → kgdebe dar error de categorías distintas. - Unidad desconocida:
3 foo → mdebe dar error de unidad desconocida.
Extensiones opcionales (si terminas rápido)
1) Sinónimos de unidades
Permite que el usuario escriba metros y lo mapeas a m, o kilometros a km.
SINONIMOS = {"metro": "m", "metros": "m", "kilometro": "km", "kilometros": "km"}def normalizar_unidad(u): u = u.lower().strip() return SINONIMOS.get(u, u)2) Tabla de conversiones permitidas
En vez de permitir cualquier par dentro de una categoría, puedes definir un conjunto explícito de pares permitidos y rechazar el resto.
PERMITIDAS = { "longitud": {("m","km"), ("km","m"), ("cm","m"), ("m","cm")}, "masa": {("kg","lb"), ("lb","kg"), ("g","kg"), ("kg","g")}}# Si activas esta regla, valida (origen, destino) antes de convertir.3) Modo “lote”
Permite ingresar varias conversiones separadas por coma y devolver una lista de resultados, aplicando las mismas reglas y precisión.