U1 - Programación en Python
1 Área y perímetro de un círculo
# Área y perímetro de un círculo
def calcular_area(radio):
pi = 3.14159
area = pi * radio ** 2
return area
def calcular_perimetro(radio):
pi = 3.14159
perimetro = 2 * pi * radio
return perimetro
def calcular_area_y_perimetro(radio):
area = calcular_area(radio)
perimetro = calcular_perimetro(radio)
return area, perimetro
calcular_area(radio=2.5)
calcular_perimetro(radio=2.5)
area, perimetro = calcular_area_y_perimetro(radio=2.5)
resultados = calcular_area_y_perimetro(radio=2.5)
print(type(area))
print(type(perimetro))
print(type(resultados))
print(type(resultados[0]))
print(type(resultados[1]))2 Promociones
# Promociones
def calcular_precio(monto, medio):
if medio == "efectivo":
monto_final = monto
elif medio == "débito":
monto_final = monto * (1 - 0.1)
elif medio == "crédito":
monto_final = monto * (1 + 0.05)
else:
print(f"El medio {medio} es desconocido.")
monto_final = monto
return monto_final
calcular_precio(80, "efectivo")
calcular_precio(80, "débito")
calcular_precio(80, "crédito")
# Extra:
# Usando valor por defecto 'efectivo'
def calcular_precio(monto, medio="efectivo"):
if medio == "efectivo":
monto_final = monto
elif medio == "débito":
monto_final = monto * (1 - 0.1)
elif medio == "crédito":
monto_final = monto * (1 + 0.05)
else:
print(f"El medio {medio} es desconocido.")
monto_final = monto
return monto_final
# Usando valor por defecto None
def calcular_precio(monto, medio=None):
if medio is None:
medio = "efectivo"
if medio == "efectivo":
monto_final = monto
elif medio == "débito":
monto_final = monto * (1 - 0.1)
elif medio == "crédito":
monto_final = monto * (1 + 0.05)
else:
print(f"El medio {medio} es desconocido.")
monto_final = monto
return monto_final3 Etapas de la vida
# Etapas de la vida
def obtener_etapa(edad):
if edad < 2:
etapa = "bebé"
elif edad < 4:
etapa = "infante"
elif edad < 13:
etapa = "niño/a"
elif edad < 20:
etapa = "adolescente"
elif edad < 65:
etapa = "adulto/a"
else:
etapa = "persona mayor"
mensaje = f"La persona es un/a {etapa}"
print(mensaje)
return None
obtener_etapa(67)
# Comentarios:
# 1. Un posible problema con esta implementación es que asume que la edad es positiva.
# También admite edades irrealmente altas.
4 Conteo de caracteres
# Conteo de caracteres
def contar_caracteres(texto):
caracteres = {}
for caracter in texto:
# No considerar espacios
if caracter == " ":
continue
# Pasar el caracter a minuscula
caracter_minuscula = caracter.lower()
if caracter_minuscula not in caracteres:
caracteres[caracter_minuscula] = 1
else:
caracteres[caracter_minuscula] += 1
return caracteres
contar_caracteres("Ahora es mejor que nunca")
# Comentarios:
# 1. Implementacion usando 'in' vs 'not in'
# 2. ¿Podrían meter el .lower en otro lado? Si, se podría pasar el texto a minúsculas antes de empezar a iterar.
# 3. ¿En cuál implementación se realizaría menos trabajo?
# 4. ¿Podriamos eliminar el `continue`?
# Moraleja: no hay una única implementación correcta.5 Orden de mérito
# Orden de mérito
notas = [
("Escalada", 9),
("Alonso", 7),
("Pérez", 8),
("Castro", 8),
("Rossini", 10),
("Martínez", 9),
("Pérez", 6),
("Riquelme", 5),
]
# Parte 1
notas_dict = {}
for registro in notas:
# Opcion 1:
notas_dict[registro[0]] = registro[1]
# Opcion 2:
# apellido = registro[0]
# nota = registro[1]
# notas_dict[apellido] = nota
# apellido, nota = registro
# notas_dict[apellido] = nota
# Pregunta: ¿Que pasa si hay dos personas con el mismo apellido?
# Parte 2
notas_dict = {}
for registro in notas:
apellido = registro[0]
nota = registro[1]
if nota not in notas_dict:
notas_dict[nota] = [apellido]
else:
notas_dict[nota].append(apellido)
# Otras opciones:
# notas_dict[nota] = notas_dict[nota] + [apellido]
# notas_dict[nota] = notas_dict[nota].extend([apellido])6 Rendimento académico
# Rendimento académico
notas = {
"Ana": [8, 9, 10],
"Luis": [6, 7, 8, 3, 9],
"Carla": [10, 9, 10],
"Marcos": [5, 6],
"Sofía": [7, 7, 8],
"Pedro": [6, 4, 5, 6, 3, 8],
"Lucía": [9, 8, 10, 9]
}
def resumir_notas(datos, modo):
resultado = {}
if modo == "promedio":
for nombre, notas in datos.items():
resultado[nombre] = sum(notas) / len(notas)
elif modo == "proporcion":
# NOTE: Esto tal vez sea un poco complicado
for nombre, notas in datos.items():
n_aprobado = 0
for nota in notas:
if nota >= 6:
n_aprobado += 1
resultado[nombre] = n_aprobado / len(notas)
else:
print(f"El modo {modo} es desconocido")
return None
return resultado
resumir_notas(notas, "promedio")
resumir_notas(notas, "proporcion")
# ¿Cómo sería la implementación sin .items()?
# ¿Podría escribir un único for loop? ¿Qué cambiaría? ¿Pros y contras?
# ¿Hay algún conflicto entre la variable 'notas' del ambiente global y la del ambiente local de
# la función?
# El cálculo de la proporción se podría abstraer en una función.
# Podría usarse un "list comprehension"
# len([nota for nota in notas if nota >= 6])
# Podría usarse un generador:
# sum(nota >= 6 for nota in notas)7 Índice de precios
ipc_2024 = [20.6, 13.2, 11.0, 8.8, 4.2, 4.6, 4.0, 4.2, 3.5, 2.7, 2.4, 2.7]
# Menor y mayor valor
min(ipc_2024)
max(ipc_2024)
# IPC promedio mensual
sum(ipc_2024) / len(ipc_2024)
# Mes de mayor inflación
ipc_2024.index(max(ipc_2024)) # 0 + 1 -> enero
# Inflación mediana
ipc_ordenado = sorted(ipc_2024)
# Opcion 1:
(ipc_ordenado[5] + ipc_ordenado[6]) * 0.5
# Opcion 2:
sum(ipc_ordenado[5:7]) * 0.5
# Opcion 3:
n_inicio = (len(ipc_ordenado) // 2) - 1 # Resto 1 porque Python indexa desde 0
n_fin = (len(ipc_ordenado) // 2 + 1) -1 # Resto 1 porque Python indexa desde 0
# Sumo 1 porque el slicing no es inclusivo por derecha
sum(ipc_ordenado[n_inicio:(n_fin + 1)]) * 0.5
# Rango de IPC sin min y max
ipc_ordenado[-1] - ipc_ordenado[0]8 Resúmenes estadísticos
def media(x):
return sum(x) / len(x)
def rango(x):
return max(x) - min(x)
# Opcion 1.
def varianza(x):
x_media = media(x)
suma = 0
for x_i in x:
suma += (x_i - x_media) ** 2
return suma / len(x)
# Opcion 2. Se podría usar un list-comprehension también.
def varianza2(x):
x_media = media(x)
distancias = []
for x_i in x:
distancias.append((x_i - x_media) ** 2)
return media(distancias)
def desvio_estandar(x):
return varianza(x) ** 0.5
def mediana(x):
x_ordenado = sorted(x)
n = len(x)
mitad = n // 2
if n % 2 == 1:
# Cantidad impar: se toma el elemento del medio
mediana = x_ordenado[mitad]
else:
# Cantidad par: se promedian los dos del medio
mediana = (x_ordenado[ - 1] + x_ordenado[mitad]) * 0.5
return mediana9 Validación de DNI
def validar_dni(dni):
# Si no 'dni' tiene puntos, es DNI válido cuando:
# - todos los caracteres sean todos dígitos
# - la longitud esté entre 7 y 8
if dni.count(".") == 0:
return dni.isdigit() and 7 <= len(dni) <= 8
# Si 'dni' tiene puntos, debe tener exactamente 2 puntos.
partes = dni.split(".")
if len(partes) != 3:
return False
# Si alguna de las partes no contiene todos dígitos, no es un DNI válido.
# Opcion 1
for parte in partes:
if not parte.isdigit():
return False
# Opcion 2
# if not all(parte.isdigit() for parte in partes):
# return False
longitudes_validas = (
len(partes[0]) in (1, 2) and
len(partes[1]) == 3 and
len(partes[2]) == 3
)
return longitudes_validas
validar_dni("40.094.127")
validar_dni("19053512")
validar_dni("6.392.780")
validar_dni("40,094,127")
validar_dni("19-053-512")
validar_dni("123456")
validar_dni("40..094127")
validar_dni("40.09412.7")10 La física del rebote
altura_inicial = 100 # metros
rebote = 3 / 5
# Parte 1 (no es necesario el uso de una variable adicional)
altura_actual = altura_inicial
for i in range(10):
altura_actual = altura_actual * rebote
print("Rebote", i + 1, "| Altura:", round(altura_actual, 4))
# Parte 2
def calcular_rebotes(altura_inicial, rebotes_n):
alturas = []
altura_actual = altura_inicial
for _ in range(rebotes_n): # '_' es una convencion cuando la variable de iteración no se usa
altura_actual = altura_actual * rebote
alturas.append(altura_actual)
return alturas
calcular_rebotes(100, 10)
# Parte 3
def calcular_rebotes(altura_inicial, rebotes_n):
alturas = []
altura_actual = altura_inicial
for _ in range(rebotes_n): # '_' es una convencion cuando la variable de iteración no se usa
altura_actual = altura_actual * rebote
alturas.append(altura_actual)
if altura_actual < 0.01:
break
return alturas
calcular_rebotes(100, 50)
len(calcular_rebotes(100, 50)) # Solo devuelve 19 rebotes
# Se podria conversar si es necesario crear 'altura_actual'
# Para el caso de las listas una opción, un poco más rebuscada, es:
def calcular_rebotes(altura_inicial, rebotes_n):
alturas = [altura_inicial * rebote]
for i in range(rebotes_n):
alturas.append(alturas[i] * rebote)
if alturas[-1] < 0.01:
break
return alturas
calcular_rebotes(100, 50)
len(calcular_rebotes(100, 50)) # Solo devuelve 19 rebotes11 Un montón de plata
billete_grosor = 0.11 * 0.001 # grosor de un billete en metros
altura_monumento = 70 # altura en metros
dias = 1
billetes_n = 1
while billetes_n * billete_grosor <= altura_monumento:
billetes_n = billetes_n * 2
dias = dias + 1
print("Se necesitan", dias, "dias.")
print("La altura de la pila es", billetes_n * billete_grosor, "metros.")
print("Se colocaron", billetes_n, "billetes.")
# Punto extra
def calcular_dias(altura_objetivo):
billete_grosor = 0.11 * 0.001
dias = 1
billetes_n = 1
while billetes_n * billete_grosor <= altura_objetivo:
billetes_n = billetes_n * 2
dias = dias + 1
return dias
calcular_dias(0.1)12 La conjetura de Collatz
def collatz(n):
# Inicializar lista con solo el valor 'n'
secuencia = [n]
while n != 1:
# Numero par
if n % 2 == 0:
n = n // 2 # Notar uso de división entera
# Numero impar
else:
# ¿Puede el resultado ser flotante?
n = 3 * n + 1
secuencia.append(n)
return secuencia
collatz(5)
collatz(20)
collatz(16)
collatz(37)
# Para discutir: ¿Podría implementarse con un 'while True'? ¿Cómo?13 Adivina el número
# Correr de la terminal con 'python {nombre_de_programa}.py'
import random
print(" ======================== Adivina el número! ======================== ")
numero_secreto = random.randint(0, 100)
mensaje = "Ingresa un numero entero: "
conteo = 0
tope_intentos = 5
while True:
numero = int(input(mensaje))
conteo += 1
if numero < numero_secreto:
mensaje = f"¡Ups! El numero secreto es mayor a {numero}. Prueba de nuevo: "
elif numero > numero_secreto:
mensaje = f"¡Ups! El numero secreto es menor a {numero}. Prueba de nuevo: "
else:
print(f"Has ganado, felicitaciones! Te llevó tan solo {conteo} intentos.")
break
if conteo == (tope_intentos - 1):
print("¡Cuidado! Te queda solo un intento.")
if conteo >= tope_intentos:
print(f"Has perdido :(. El numero secreto era {numero_secreto}.")
break14 Conteo de caracteres Pythonico
def contar_caracteres(texto):
texto = texto.lower() # Pasa a minuscula al principio
caracteres = {}
for caracter in texto:
# Solo considerar letras del alfabeto
if not caracter.isalpha():
continue
# Si el caracter no esta en el diccionario, devuelve 0
# Si está, devuelve su conteo.
# En ambos casos, le suma 1.
caracteres[caracter] = caracteres.get(caracter, 0) + 1
return caracteres
contar_caracteres("Ahora es mejor que nunca")
contar_caracteres("Ahora es mejor que nunca!! +_")
contar_caracteres("Ahora es mejor que nunca!! +_") == contar_caracteres("Ahora es mejor que nunca")
15 Validador de contraseñas 😱
CARACTERES_ESPECIALES = "@#$%^&*()"
def contiene_letra(texto):
# True si al menos un caracter es una letra
for caracter in texto:
if caracter.isalpha():
return True
return False
def contiene_numero(texto):
# True si al menos un caracter es un numero (del sistema decimal)
for caracter in texto:
if caracter.isdecimal():
return True
return False
def contiene_especial(texto):
# True si al menos un caracter es un numero
for caracter in texto:
if caracter in CARACTERES_ESPECIALES:
return True
return False
def validar_pwd(pwd):
errores = []
if not (8 <= len(pwd) <= 24):
errores.append("Debe tener entre 8 y 24 caracteres.")
if not contiene_letra(pwd):
errores.append("Debe contener al menos una letra.")
if not contiene_numero(pwd):
errores.append("Debe contener al menos un número.")
if not contiene_especial(pwd):
errores.append("Debe contener al menos un carácter especial '@#$%^&*()'.")
caracteres_desconocidos = []
for caracter in pwd:
# Hablar sobre si es posible simplificar esto
if (not caracter.isdecimal()) and (not caracter.isalpha()) and (caracter not in CARACTERES_ESPECIALES):
caracteres_desconocidos.append(caracter)
# Equivale a len(caracteres_desconocidos) > 0
if caracteres_desconocidos:
errores.append(
f"La contraseña contiene los siguientes caracteres desconocidos {caracteres_desconocidos}"
)
if errores == []:
return True
return errores
while True:
password = input("Ingrese una contraseña (o ENTER para salir): ")
if password == "":
print("Operación cancelada.")
break
resultado = validar_pwd(password)
# Acá NO se puede usar 'if es_valida'.
if resultado is True:
print("Contraseña válida.")
break
print("La contraseña no es válida:")
for error in resultado:
print("-", error)16 Conteo de caracteres II 😱
def contar_caracteres(texto, orden="aparicion"):
texto = texto.lower() # Pasa a minuscula al principio
caracteres = {}
for caracter in texto:
# Solo considerar letras del alfabeto
if not caracter.isalpha():
continue
# Si el caracter no esta en el diccionario, devuelve 0
# Si está, devuelve su conteo.
# En ambos casos, le suma 1.
caracteres[caracter] = caracteres.get(caracter, 0) + 1
if orden == "aparicion":
salida = caracteres
elif orden == "alfabetico":
salida = {}
claves = sorted(caracteres.keys()) # No hace falta el .keys() en realidad
for clave in claves:
salida[clave] = caracteres[clave]
elif orden == "frecuencia":
salida = {}
claves = list(caracteres.keys()) # No hace falta el .keys() en realidad
claves_ordenadas = sorted(claves, key=lambda k: caracteres[k], reverse=True)
for clave in claves_ordenadas:
salida[clave] = caracteres[clave]
return salida
contar_caracteres("Ahora es mejor que nunca", "aparicion")
contar_caracteres("Ahora es mejor que nunca", "alfabetico")
contar_caracteres("Ahora es mejor que nunca", "frecuencia")