Vamos a afianzar los conocimientos de Python que acabamos de adquirir haciendo algunos ejercicios, y así retener las peculiaridades de la sintaxis y aclarar algunos detalles a tener en cuenta cuando se trabaja en modo interactivo.
Vamos a escribir ahora una función que sume los n
primeros números naturales. Observa que podemos escribir una cadena de documentación (docstring) justo debajo de la definición de la función para explicar lo que hace.
def sumatorio(num):
"""Suma los `num` primeros números.
Ejemplos
--------
>>> sumatorio(4)
10
"""
suma = 0
for nn in range(1, num + 1):
suma = nn + suma
return suma
Lo que hemos hecho ha sido inicializar el valor de la suma a 0 e ir acumulando en ella los num
primeros números naturales.
sumatorio(4)
10
help(sumatorio)
Help on function sumatorio in module __main__: sumatorio(num) Suma los `num` primeros números. Ejemplos -------- >>> sumatorio(4) 10
def sumatorio_mal(num):
for nn in range(1, num + 1):
suma = nn + suma
return suma
sumatorio_mal(4)
--------------------------------------------------------------------------- UnboundLocalError Traceback (most recent call last) <ipython-input-5-9882aa9a55e2> in <module>() ----> 1 sumatorio_mal(4) <ipython-input-4-d575a2b0e54e> in sumatorio_mal(num) 1 def sumatorio_mal(num): 2 for nn in range(1, num + 1): ----> 3 suma = nn + suma 4 return suma UnboundLocalError: local variable 'suma' referenced before assignment
Para comprobar el resultado correcto, nada como acudir a la función sum
de Python, que suma los elementos que le pasemos:
list(range(1, 4 + 1))
[1, 2, 3, 4]
sum(range(1, 4 + 1))
10
Ahora nuestra función es un poco más rara: tiene que sumar números naturales consecutivos y no pasarse de un determinado límite. Además, queremos el valor de la suma.
def suma_tope(tope):
"""Suma números naturales consecutivos hasta un tope.
"""
suma = 0
nn = 1
while suma + nn <= tope:
suma = suma + nn
nn += 1
return suma
suma_tope(9)
6
suma_tope(9) == 1 + 2 + 3
True
suma_tope(10) == 1 + 2 + 3 + 4
True
La palabra clave assert
recibe una expresión verdadera o falsa, y falla si es falsa. Si es verdadera no hace nada, con lo cual es perfecto para hacer comprobaciones a mitad del código que no estorben mucho.
assert suma_tope(11) == 1 + 2 + 3 + 4
assert suma_tope(10 + 5) == 1 + 2 + 3 + 4
--------------------------------------------------------------------------- AssertionError Traceback (most recent call last) <ipython-input-13-7e20f9ee8a4a> in <module>() ----> 1 assert suma_tope(10 + 5) == 1 + 2 + 3 + 4 AssertionError:
La normativa de exámenes es: "si un examen dura más de 3 horas, entonces debe tener un descanso". Los argumentos de la función son el tiempo en horas y un valor True
o False
que indica si hay descanso o no.
def cumple_normativa(tiempo, descanso):
"""Comprueba si un examen cumple la normativa de la UPM.
"""
if tiempo <= 3:
return True
else:
#if descanso:
# return True
#else:
# return False
return descanso # ¡Equivalente!
cumple_normativa(2, False)
True
if not cumple_normativa(5, descanso=False):
print("¡Habla con DA!")
¡Habla con DA!
Hallar $x = \sqrt{S}$.
http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
def raiz(S):
x = S / 2
while True:
temp = x
x = (x + S / x) / 2
if temp == x:
return x
Aquí estoy usando un truco de la aritmética en punto flotante: como la convergencia se alcanza rápidamente, llega un momento en que el error es menor que la precisión de la máquina y el valor no cambia de un paso a otro.
raiz(10)
3.162277660168379
import math
math.sqrt(10)
3.1622776601683795
raiz(10) ** 2
9.999999999999998
math.sqrt(10) ** 2
10.000000000000002
Ahora tienes curiosidad, ¿verdad? :) http://puntoflotante.org/
Secuencia de Fibonacci: $F_n = F_{n - 1} + F_{n - 2}$, con $F_0 = 0$ y $F_1 = 1$.
$$0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...$$Con iteración:
def fib(n):
a, b = 0, 1
for i in range(n):
a, b = b, a + b # Bendita asignación múltiple
return a
fib(0), fib(3), fib(10)
(0, 2, 55)
Con recursión:
def fib_recursivo(n):
if n == 0:
res = 0
elif n == 1:
res = 1
else:
res = fib_recursivo(n - 1) + fib_recursivo(n - 2)
return res
Imprimir una lista con los $n$ primeros:
def n_primeros(n):
F = fib_recursivo
lista = []
for ii in range(n):
lista.append(F(ii))
return lista
n_primeros(10)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Implementar el sistema de reparto de escaños d'Hondt. Dicho sistema se basa en ir repartiendo escaños consecutivamente al partido con el máximo coeficiente, $c_i = \frac{V_i}{s_i + 1}$, donde $V_i$ es el número total de votos obtenido por del partido $i$, mientras que $s_i$ es el número de escaños asignados dicho partido (0 al comenzar el reparto).
Veamos por ejemplo el caso expuesto en Wikipedia:
Partido | Partido A | Partido B | Partido C | Partido D | Partido E |
---|---|---|---|---|---|
Votos | 340000 | 280000 | 160000 | 60000 | 15000 |
Todavía no hay ningún escaño asignado, así que los votos de cada partido se dividen por 1:
Partido | Partido A | Partido B | Partido C | Partido D | Partido E |
---|---|---|---|---|---|
Votos | 340000 | 280000 | 160000 | 60000 | 15000 |
Escaño 1 | 340000 | 280000 | 160000 | 60000 | 15000 |
Y por tanto el partido A recibe el primer escaño. Para repartir el segundo escaño se vuelven a dividr por 1 los votos de cada partido, salvo el partido A que se divide por 2, pues ya tiene un escaño:
Partido | Partido A | Partido B | Partido C | Partido D | Partido E |
---|---|---|---|---|---|
Votos | 340000 | 280000 | 160000 | 60000 | 15000 |
Escaño 1 | 340000 | 280000 | 160000 | 60000 | 15000 |
Escaño 2 | 170000 | 280000 | 160000 | 60000 | 15000 |
Así pues, el segundo escaño va para el partido B. Si se reparten 7 escaños como en el ejemplo de Wikpedia, la tabla final quedaría como sigue:
Partido | Partido A | Partido B | Partido C | Partido D | Partido E |
---|---|---|---|---|---|
Votos | 340000 | 280000 | 160000 | 60000 | 15000 |
Escaño 1 | 340000 | 280000 | 160000 | 60000 | 15000 |
Escaño 2 | 170000 | 280000 | 160000 | 60000 | 15000 |
Escaño 3 | 170000 | 140000 | 160000 | 60000 | 15000 |
Escaño 4 | 113333 | 140000 | 160000 | 60000 | 15000 |
Escaño 5 | 113333 | 140000 | 80000 | 60000 | 15000 |
Escaño 6 | 170000 | 93333 | 80000 | 60000 | 15000 |
Escaño 7 | 85000 | 93333 | 80000 | 60000 | 15000 |
Así que los partidos A y B obtendrían 3 escaños, mientras que el partido C obtendría 1 único escaño, quedando el resto de partidos fuera del proceso.
def hondt(votos, n):
s = [0] * len(votos)
for i in range(n):
c = [v[j] / (s[j] + 1) for j in range(len(s))]
s[c.index(max(c))] += 1
return s
v = [340000, 280000, 160000, 60000, 15000]
n = 7
hondt(v, n)
[3, 3, 1, 0, 0]
En esta clase hemos visto cómo crear funciones que encapsulen tareas de nuestro programa y las hemos aplicado para respondernos ciertas preguntas sencillas.
Referencias
Las siguientes celdas contienen configuración del Notebook
Para visualizar y utlizar los enlaces a Twitter el notebook debe ejecutarse como seguro
File > Trusted Notebook
# Esta celda da el estilo al notebook
from IPython.core.display import HTML
css_file = '../styles/aeropython.css'
HTML(open(css_file, "r").read())