Clase 02 · 30 minGratis

Cifrado César: de script a función

Clase 2 del curso gratis de buenas prácticas en Python: implementamos el cifrado César, vemos por qué Pylint castiga los nombres de una letra y pasamos de programación estructural a funcional.

Toca cualquier marca ▸ 0:00 de los apuntes y el video salta a ese momento. Abrir en YouTube

Qué es un cifrado César

Cada letra se reemplaza por la que está clave posiciones más adelante en el alfabeto. Con clave 1, la A pasa a B y la B a C; mamá queda como NBNB. Cuando se llega al final, se da la vuelta: con clave 1, la Z vuelve a ser A.

Como trabajamos en español, nuestro alfabeto incluye la Ñ: 27 letras. Muchas implementaciones de internet la ignoran, y eso cambia los resultados.

Nombres de una letra: el error a propósito

La primera versión se escribe mal adrede, con variables X, Y y Z. Pylint la califica con 0/10 , y con razón:

  • Las constantes van en MAYÚSCULAS (ALFABETO, MENSAJE).
  • Un nombre de una letra no le dice nada a tu yo del futuro.
  • Las variables van en snake_case (texto_cifrado), no en camelCase (textoCifrado, más típico de Java) .

El Zen de Python lo resume: explícito es mejor que implícito .

El algoritmo

Recorremos el texto letra por letra, buscamos su posición en el alfabeto, le sumamos la clave y tomamos la letra de la nueva posición. Lo que no es letra (espacios, signos, números) pasa tal cual.

El truco para dar la vuelta al alfabeto es el módulo % : 27 % 27 es 0 y 28 % 27 es 1, así que el resultado nunca se sale de las 27 posiciones.

Repetir código es la señal

Para descifrar, la primera tentación es copiar el bloque y cambiarle el signo. Eso funciona, pero es programación estructural: todo en un archivo, todo seguido . Hay otros paradigmas (reactivo, orientado a objetos); aquí usamos el funcional: si algo se repite, debe ser una función .

python
"""
Modulo para hacer cifrado cesar
"""
def cifrado_cesar(texto, clave):
    """función que implementa algoritmo de cifrado cesar

    Args:
        texto (str): texto a ser procesado/cifrado
        clave (int): clave de cifrado

    Returns:
        str: texto procesado/cifrado
    """
    alfabeto = "ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"
    texto_cifrado = ""
    for letra in texto.upper():
        if letra in alfabeto:
            posicion = alfabeto.index(letra)
            nueva_posicion = (posicion + clave) % len(alfabeto)
            texto_cifrado += alfabeto[nueva_posicion]
        else:
            texto_cifrado += letra
    return texto_cifrado

Y aparece la ventaja: descifrar es la misma función con la clave negativa . cifrado_cesar("IPMB", -1) devuelve HOLA.

Con el docstring de la función, Pylint vuelve a 10/10 . Al empezar la clase 3, la función se muda a su propio archivo.

El reto de esta clase

Escribe una función descifrado_cesar(texto, clave) que no duplique lógica, y comprueba a mano que descifrado_cesar(cifrado_cesar("hola mundo", 7), 7) devuelve HOLA MUNDO.

Ver una solución posible
python
from funciones.cifrado_cesar import cifrado_cesar


def descifrado_cesar(texto, clave):
    """Deshace el cifrado César aplicando la misma función con la clave negativa."""
    return cifrado_cesar(texto, -clave)


print(descifrado_cesar(cifrado_cesar("hola mundo", 7), 7))  # HOLA MUNDO

Sigue con la clase 3

Pruebas unitarias con pytest

Seguir el canal de WhatsApp