Contenedores, Funciones, Loops#

  • Contenedores Tuple

  • Funciones

  • La Instrucción for

  • Nociones Adicionales

Introducción#

Tratemos de hacer algo útil con lo que ya sabemos. Por ejemplo, calculemos el promedio de los resultados diarios en trading en una semana. Supongamos entonces que los resultados son los siguientes (en una unidad monetaria cualquiera): 100, 110, -150, 200, 250. Para calcular el promedio, tenemos que sumar los 5 resultados y dividirlos por 5. Hagamos ese cálculo en la siguiente celda.

(100 + 110 - 150 + 200 + 250) / 5
102.0

Tenemos el resultado, pero no hicimos nada muy astuto, simplemente utilizamos Python como si fuera una calculadora. Vamos mejorando de a poco, el objetivo es construir una pequeña herramienta (que será una función) que nos permita calcular lo más cómodamente posible el promedio de un conjunto de datos.

Cada Resultado es una Variable#

Asignamos cada nota a una variable:

res1 = 100
res2 = 110
res3 = -150
res4 = 200
res5 = 250

Sólo ahí calculamos el promedio:

(res1 + res2 + res3 + res4 + res5) / 5
102.0

¿Qué ganamos con esto? Un poco más de generalidad, si cambia el valor de un resultdo, sólo tenemos que cambiar el valor asignado a la variable que le corresponde. Por ejemplo, si res1 sube a 120 haremos lo siguiente:

res1 = 120
(res1 + res2 + res3 + res4 + res5) / 5
106.0

¿Qué pasa si ahora son más resultados? Por ejemplo, queremos calcular el promedio de 2 semanas. En ese caso podríamos hacer lo siguiente para calcular el promedio:

res6 = 115
res7 = -200
res8 = -120
res9 = 200
res10 = 50
(res1 + res2 + res3 + res4 + res5 + res6 + res7 + res8 + res9 + res10) / 10
57.5

Resulta, pero no es muy general, si después quisiéramos el resultado promedio del mes tendríamos que agregar unas 10 variables más y dividir por 20. Además, todo eso lo haríamos a mano (una manera de pensar en la generalidad de la herramienta que queremos diseñar es considerar el trabajo adicional que hay que hacer para calcular un nuevo caso).

Las Variables de Tipo List#

Una List es simplemente una lista de valores, pueden ser números, strings u otros tipos. Incluso, una List puede contener una List. Veamos ejemplos:

edades = [22, 36, 41, 52]
edades
[22, 36, 41, 52]
type(edades)
list
nombres_apellidos = ["Pedro", "Pablo", "Perez", "Pereira"]
nombres_apellidos
['Pedro', 'Pablo', 'Perez', 'Pereira']
nombres_edades = ["Juan", 75, "Claudia", 42] # es un contenedor heterogéneo
nombres_edades
['Juan', 75, 'Claudia', 42]

Los elementos de una lista se cuentan desde el 0 en adelante. Por ejemplo, en edades la edad 0 es 22, la número 1 es 36, la número 2 es 41 y la número 3 es 52.

Se puede obtener un elemento de una lista de la siguiente forma:

edades[0] # Se parte contando desde 0. El primer elemento es el número 0.
22
edades[3]
52

Se puede cambiar el valor de un elemento de una List.

edades[3] = 66 # Las List son mutables. Significa que, después de ser definidas, pueden cambiar.
edades
[22, 36, 41, 66]

Si trato de obtener un elemento que no existe, voy a obtener un error:

edades[4]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Cell In[15], line 1
----> 1 edades[4]

IndexError: list index out of range

Fijarse bien en el mensaje de error IndexError: list index out of range, está diciendo que el índice que usamos (en este caso 4) está fuera de rango, o sea la lista no tiene un elemento de índice 4.

Podemos alargar una lista:

edades
[22, 36, 41, 66]
edades.append(76) # append = agregar a la cola
edades
[22, 36, 41, 66, 76]

Es segunda vez que vemos la notación “.” (notas.append). Por ahora no vamos a explicar su significado completo (es parte de lo relacionado a programación orientada a objetos), pero podemos pensar que append es una función que se puede aplicar a una variable de tipo List y que permite agregar un valor a esa variable.

¿Qué ganamos con tener las variables en una List? Hay un par de funciones que nos ayudan a hacer más general el cálculo de promedio:

sum(edades) # Sólo resulta con List que sólo contengan números.
241

Con la función sum podemos obtener la suma de los elementos de la lista, si la List sólo contiene números, con otro tipo de elementos se va a producir un error.

sum(nombres_apellidos)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-22-3ca1c3249b9a> in <module>
----> 1 sum(nombres_apellidos)

TypeError: unsupported operand type(s) for +: 'int' and 'str'

También tenemos la función len que cacula el número de elementos de una List.

len(edades) # Funciona con cualquier List
5

Con estas dos funciones, el cálculo del promedio se puede escribir como:

sum(edades) / len(edades)
48.2

Verifiquémoslo:

edades
[22, 36, 41, 66, 76]
(22 + 36 + 41 + 66 + 76) / 5
48.2

¡Impecable! Funciona como queríamos. Nos va faltando un elemento, ¿podemos dejar guardado en una variable el cálculo de promedio? Así lo podemos reutilizar sin tener que volver a escribirlo. La respuesta es sí, tenemos que definir una función.

Las Variables de Tipo Tuple#

Una Tuple también es una lista de valores, pueden ser números, strings u otros tipos. Incluso, una Tuple puede contener una Tuple. La diferencia con una List es que las variables de tipo Tuple son inmutables, una vez que se definen, no pueden cambiar.

Veamos ejemplos:

edades = (22, 36, 41, 52) # <--- Notar que se usan () y no []
edades
(22, 36, 41, 52)
nombres_apellidos = ("Pedro", "Pablo", "Perez", "Pereira")
nombres_apellidos
('Pedro', 'Pablo', 'Perez', 'Pereira')
nombres_edades = ("Juan", 75, "Claudia", 42) # es un contenedor heterogéneo
nombres_edades
('Juan', 75, 'Claudia', 42)

Las Tuple son inmutables:

edades[0] = 23
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-43-057c74ed62c5> in <module>
----> 1 edades[0] = 23

TypeError: 'tuple' object does not support item assignment

Si quiero cambiar un valor, tengo que redefinir el contenido de toda la variable.

edades = (23, 36, 41, 52)

Tampoco se puede agregar un valor.

edades.append(60)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-61-90054cd3b677> in <module>
----> 1 edades.append(60)

AttributeError: 'tuple' object has no attribute 'append'

Funciones#

En matemáticas decimos que una función \(f:X \rightarrow Y\) es una regla de cálculo que asocia a cada \(x \in X\) un elemento \(y \in Y\). El primer tipo de función que aprendemos es una función lineal \(L: \mathbb{R} \rightarrow \mathbb{R}\), por ejemplo:

\[L(x) = 2x + 3\]

La primera que función que vamos a crear será la función \(promedio: List[Number] \rightarrow Number\). O sea, una función que a cada List que sólo tenga números como elementos asocia un número.

def promedio(numeros):
    return sum(numeros) / len(numeros)
type(promedio)
function

Fijarse bien en los 4 espacios que hay antes de la línea return, son indispensables, si no están se producirá un error. Al haber declarado la función promedio en la línea anterior, Python espera que en la línea siguiente comience la definición de la función, dicha definición tiene que que estar en líneas indentadas (con una sangría) de 4 espacios. Después del return se puede volver a escribir alineado a la izquierda sin indentación.

def promedio_malo(numeros):
return sum(numeros) / len(numeros)
  File "<ipython-input-31-448e236ccfd3>", line 2
    return sum(numeros) / len(numeros)
         ^
IndentationError: expected an indented block

Para definir una función:

  • partimos con def,

  • luego un espacio y el nombre que queremos darle a la función

  • luego, entre paréntesis, el nombre del argumento de la función

  • al final de esa línea un “:”

  • las líneas que vienen tienen que partir con 4 espacios (Jupyter las mete automáticamente)

  • la última línea de la función comienza con return ahí se define el resultado de aplicar la función a su argumento

Hagamos la prueba,

promedio(edades)
48.2

Por último, podemos lograr que el output sea un formato más ordenado usando la instrucción format o un fstring.

mensaje = "El promedio de edades es: {0:.2f}" # Lo que está entre {} indica que ahí va una variable,
                                             # el 0 indica que es la primera los : separan el número
                                             # de variable de su formato para imprimir y la expresión
                                             # .2f indica que se imprimirá con 2 decimales (f de flotante).

Si hacemos directamente print(mensaje) obtenemos:

print(mensaje)
El promedio de edades es: {0:.2f}

Al aplicar format se obtiene:

print(mensaje.format(promedio(edades)))
El promedio de edades es: 48.20

Hagamos lo mismo, pero con un fstring.

mensaje2 = f"El promedio de edades es: {promedio(edades):.2f}"
print(mensaje2)
El promedio de edades es: 48.20

Ejercicios#

No mirar las soluciones antes de haber tratado de resolver los ejercicios. Si después de tratar un rato no lo has resuelto, sí se puede mirar la solución, pero si lo haces antes de tratar, la respuesta entrará por una oreja y saldrá por la otra.

Ejercicio#

Escriba una función en Python que implemente la siguiente función matemática \(f: \mathbb{R} \rightarrow \mathbb{R}\), \(f(x) = 2x+3\).

def f(x):
    return 2*x + 3
x = [2, 2.7]
print("El valor de f calculada en {} es: {}".format(x[0], f(x[0])))
print("El valor de f calculada en {} es: {}".format(x[1], f(x[1])))

Ejercicio#

Escriba una función en Python que implemente la siguiente función matemática \(g: \mathbb{R^2} \rightarrow \mathbb{R}\), \(g(x,y) = 2x+3y+1\).

def g(x, y):
    return 2*x +3*y + 1

La Instrucción for#

Consideremos la siguiente situación, tenemos una posición en un depósito a plazo en CLP que vence en 365 días más y queremos sensibilizar el valor del depósito para varias tasas de descuento.

monto = 1000000000
plazo = 365
tasas = [.01, .0125, .015, .0175, .02] # Tasas lineales Act360.

La instrucción for nos permite recorrer secuencialmente la List tasas y calcular el valor presente del depósito para cada uno de los valores ahí almacenados.

for tasa in tasas: # <--- Notar la indentación en la línea siguiente.
    print(f"El valor del depósito para una tasa del {tasa:,.2%} es: {monto / (1 + tasa * plazo / 360):,.0f}")
El valor del depósito para una tasa del 1.00% es: 989,962,876
El valor del depósito para una tasa del 1.25% es: 987,484,999
El valor del depósito para una tasa del 1.50% es: 985,019,495
El valor del depósito para una tasa del 1.75% es: 982,566,272
El valor del depósito para una tasa del 2.00% es: 980,125,238

Podemos definir una función que almacene estos resultados en una List y retorne esa List.

def sens_depo(monto, plazo, tasas):
    resultado = []
    for tasa in tasas:
        resultado.append(monto / (1 + tasa * plazo / 360))
    return resultado
sens_depo(monto, plazo, tasas)
[989962876.3921353,
 987484999.1428081,
 985019495.1775088,
 982566272.0480366,
 980125238.2248843]

Nociones Adicionales#

En Python un string (tipo str) se comporta como una Tuple de caracteres de texto. Por ejemplo,

str1 = "Python"

Es inmutable.

str1[0] = 'p'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-48-11281795b35c> in <module>
----> 1 str1[0] = 'p'

TypeError: 'str' object does not support item assignment

Puedo obtener el caracter en la posición n igual que en una Tuple (o una List).

x = [2, 2.7]
y = (1.3, 3.14)
print("El valor de g calculada en ({}, {}) es: {}".format(x[0], y[0], g(x[0], y[0])))
print("El valor de g calculada en ({}, {}) es: {}".format(x[1], y[1], g(x[1], y[1])))
El valor de g calculada en (2, 1.3) es: 8.9
El valor de g calculada en (2.7, 3.14) es: 15.82
str1[1]
'y'

También puedo calcular el número de caracteres con la función len.

len(str1)
6

Sin embargo, también hay funciones específicas para un str, como la función format que ya vimos y las dos funciones que mostramos a continuación:

str1.upper()
'PYTHON'
str1.lower()
'python'

Existe también una funcionalidad que en inglés se llama slice (o rebanar) y que se aplica tanto a las List como a las str y a las Tuple.

lista = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(lista[1:])         # Desde el primero en adelante
print(lista[0:3])        # Desde el 0 inclusive hasta el 3 no inclusive
print(lista[:-1])        # Del primero al último no inclusive
print(lista[-1:])        # El último
print(lista[-2:])        # Desde el penúltimo en adelante
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[9]
[8, 9]

También aplica a un str.

str2 = "esdrújula"
print(str2[1:])         # Desde el primero en adelante
print(str2[0:3])        # Desde el 0 inclusive hasta el 3 no inclusive
print(str2[:-1])        # Del primero al último no inclusive
print(str2[-1:])        # El último
print(str2[-2:])        # Desde el penúltimo en adelante
sdrújula
esd
esdrújul
a
la

Y a una Tuple. Notar que, en este caso, el slice de la Tuple es una Tuple.

tupla = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
print(tupla[1:])         # Desde el primero en adelante
print(tupla[0:3])        # Desde el 0 inclusive hasta el 3 no inclusive
print(tupla[:-1])        # Del primero al último no inclusive
print(tupla[-1:])        # El último
print(tupla[-2:])        # Desde el penúltimo en adelante
(1, 2, 3, 4, 5, 6, 7, 8, 9)
(0, 1, 2)
(0, 1, 2, 3, 4, 5, 6, 7, 8)
(9,)
(8, 9)

Ejercicio#

Escriba una función en Python que tenga como argumento un str (una palabra) y devuelva como resultado la str inicial con el primer caracter (y sólo el primer caracter) en mayúsculas.

def primer_en_mayus(palabra):
    primera_letra_mayus = palabra[0].upper()
    resto_palabra = palabra[1:]
    resultado = primera_letra_mayus + resto_palabra
    return resultado
palabras = [str2, "onomatopeya", "español"]
print("{} ---> {}".format(palabras[0], primer_en_mayus(palabras[0])))
print("{} ---> {}".format(palabras[1], primer_en_mayus(palabras[1])))
print("{} ---> {}".format(palabras[2], primer_en_mayus(palabras[2])))
esdrújula ---> Esdrújula
onomatopeya ---> Onomatopeya
español ---> Español