Autor: Luis Fernando Apáez Álvarez
-Curso PyM-
Clase 6 (Parte 1): Funciones
Fecha: 13 de Agosto del 2022
En clases anteriores vimos una breve introducción al concepto de función. Vimos que éstas pueden o no tener parámetros y pueden devolver o no un resultado. En resumen, abordamos la manera básica del manejo de funciones en Python y la idea intuitiva de cómo éstas actúan.
Por ejemplo, definimos la función matemática $f(x)=x^{2}$ en Python como sigue:
# funcion para calcular un numero al cuadrado
def f(x):
return x ** 2
# ponemos a prueba nuestra funcion
print(f(2))
print()
print(f(67))
4 4489
Bajo el concepto de las funciones matemáticas, podemos realizar sus gráficos, lo cual podemos hacer en Python utilizando la librería matplotlib
# Importamos la libreria necesaria
import matplotlib.pyplot as plt
# Configuramos un estilo de graficacion
plt.style.use("ggplot")
# Valores que tomara la x (valores del eje x)
# -2, -1.99, -1.98, . . ., 0, 0.01, 0.02, . . ., 2
x_values = [-2 + 0.01 * i for i in range(0, 401)]
# Valores que tomara la funcion en el eje y
# (-2)^2, (-1.99)^2, (-1.98)^2, . . ., (0)^2, (0.01)^2, (0.02)^2, . . ., (2)^2
y_values = [f(x) for x in x_values]
# Creamos el gráfico
plt.plot(x_values, y_values)
# Etiquetas
plt.xlabel("Eje x")
plt.ylabel("Eje y")
# Dentro de nuestro titulo podemos ocupar codigo LaTeX
plt.title("Función: $f(x)=x^{2}$", fontsize=14)
plt.show()
En realidad el gráfico anterior es un diagrama de líneas entre muchos puntos, pero, dado que creamos muchos puntos los cuales son muy muy cercanos entre sí, entonces vemos una curva. Probemos graficando menos puntos:
# Valores que tomara la x (valores del eje x)
# -2, -1.9, -1.8, . . . , 0, 0.1, 0.2, . . ., 2
x_values = [-2 + 0.1 * i for i in range(0, 41)]
# Valores que tomara la funcion en el eje y
# (-2)^2, (-1.9)^2, (-1.8)^2, . . . , 0, (0.1)^2, (0.2)^2, . . ., (2)^2
y_values = [f(x) for x in x_values]
# Creamos el gráfico
plt.plot(x_values, y_values)
# Etiquetas
plt.xlabel("Eje x")
plt.ylabel("Eje y")
# Dentro de nuestro titulo podemos ocupar codigo LaTeX
plt.title("Función: $f(x)=x^{2}$", fontsize=14)
plt.show()
De nuevo tenemos muchos puntos muy cercanos entre sí, por lo cual continuamos viendo una curva. Disminuiremos aún más el número de puntos
# Valores que tomara la x (valores del eje x)
# -2, -1.5, . . ., 0, . . . 2
x_values = [-2 + 0.5 * i for i in range(0, 9)]
# Valores que tomara la funcion en el eje y
y_values = [f(x) for x in x_values]
# Creamos el gráfico
plt.plot(x_values, y_values)
# Etiquetas
plt.xlabel("Eje x")
plt.ylabel("Eje y")
# Dentro de nuestro titulo podemos ocupar codigo LaTeX
plt.title("Función: $f(x)=x^{2}$", fontsize=14)
plt.show()
En este caso es más notorio que el gráfico con el cual estamos trabajando es en realidad un gráfico de líneas.
Ahora bien, para trabajar con fuciones trigonométricas, exponenciales o logarítmicas, podemos utilizar la librería NumPy
, la cual puede ser utilizada para cálculo numérico. Más adelante veremos a detalle dicha librería, pero por ahora la utilizaremos para poder trabajar con el tipo de funciones matemáticas que mencionamos antes:
# importacion necesaria
import numpy as np
# funcion seno: np.sin()
# funcion coseno: np.cos()
# funcion tangente: np.tan()
# funcion exponencial: np.exp()
# funcion logaritmica: np.log()
# numero pi: np.pi
print(f"El valor del número pi es: {np.pi}")
El valor del número pi es: 3.141592653589793
Así, podemos graficar la función $f(x)=sin(x)$:
# Valores que tomara la x (valores del eje x)
# creamos un rango de -2*pi a 2*pi:
x_values = [-2 * np.pi + 0.01 * i * np.pi for i in range(0, 401)]
# Valores que tomara la funcion en el eje y
# En este caso usaremos la funcion np.sin()
y_values = [np.sin(x) for x in x_values]
# Creamos el gráfico para la funcion seno
plt.plot(x_values, y_values, color="#00A8F4")
# Etiquetas
plt.xlabel("Eje x")
plt.ylabel("Eje y")
# Dentro de nuestro titulo podemos ocupar codigo LaTeX
plt.title("Función: $f(x)=sin(x)$", fontsize=14)
plt.show()
# Valores que tomara la x (valores del eje x)
# creamos un rango de -2 a 2
x_values = [-2 + 0.1 * i for i in range(0, 41)]
# Valores que tomara la funcion en el eje y
# En este caso usaremos la funcion np.exp()
y_values = [np.exp(x) for x in x_values]
# Creamos el gráfico
plt.plot(x_values, y_values, color="#0019F4")
# Etiquetas
plt.xlabel("Eje x")
plt.ylabel("Eje y")
# Dentro de nuestro titulo podemos ocupar codigo LaTeX
plt.title("Función: $f(x)=e^{x}$", fontsize=14)
plt.show()
Por otro lado, podemos crear una función para convertir grados kelvin a grados centígrados. Los grados Kelvin comienzan en cero, donde cero grados Kelvin equivalen a -273.15 grados centigrados. Ahora bien, es una buena práctica especificar (o describir brevemente) qué es lo que hacen las funciones que definimos, para ello utilizaremos triples comillas dobles como veremos a continuación:
# Definiremos una funcion que convierte grados kelvin a
# centrigrados
def conversor(num_kelvin):
# Pequenia descripcion de lo que hace nuestra funcion:
"""Esta función recibe como parámetro un número
correspondiente a grados kelvin y retorna su
equivalente en grados centigrados
"""
# convertimos num_kelvin a centigrados:
num_celsius = num_kelvin - 273.15
return num_celsius
# Ponemos a prueba nuestra funcion:
print(f"0 grados kelvin son {conversor(0)} grados celsius")
print(f"78 grados kelvin son {conversor(78)} grados celsius")
0 grados kelvin son -273.15 grados celsius 78 grados kelvin son -195.14999999999998 grados celsius
Otra buena práctica es especificar el tipo de dato que retornará nuestra función. Por ejemplo, la función anterior retorna un número decimal por lo cual podemos especificar que dicha función retorna un flotante:
# Especificaremos el tipo de retorno, para ello
# colocaremos: -> <tipo de dato de retorno>
# Por ejemplo
# -> <tipo de dato de retorno>
def conversor(num_kelvin) -> float:
# Pequenia descripcion de lo que hace nuestra funcion:
"""Esta función recibe como parámetro un número
correspondiente a grados kelvin y retorna su
equivalente en grados centigrados
"""
# convertimos num_kelvin a centigrados:
num_celsius = num_kelvin - 273.15
return num_celsius
Dicha indicación es opcional de poner, pero es una buena práctica ponerla. Asimimo, aunque lo hayamos colocado, nuestra función puede devolver otro tipo de dato al especificado, lo cual no sería una buena práctica; lo que buscamos es que el código que escribamos este en sintonía, así como el código de la función conversor()
.
Crearemos ahora una función que nos diga si un estudiante: ha aprobado (calificación 6-8), ha aprobado con excelente nota (calificación 9-10) y no ha aprobado (calificación menor a 6).
def calificador(nota) -> str:
"""Función que recibe como parámetro un número
y devuelve un mensaje (str), dependiendo el número ingresado.
Esta función nos dirá si un estudiante ha aprobado, aprobado
con excelente nota, o si el estudiante no aprobó.
"""
# Implementamos un if-elif
if nota < 6:
return "El estudiante no ha aprobado :("
elif (nota >= 6) and (nota < 9):
return "El estudiante ha aprobado :)"
else:
return "El estudiante ha aprobado con excelente nota :o"
# Ponemos a prueba nuestra funcion
print(calificador(0))
print()
print(calificador(7))
print()
print(calificador(9.2))
El estudiante no ha aprobado :( El estudiante ha aprobado :) El estudiante ha aprobado con excelente nota :o
Recordemos que en una función podemos considerar agregar parámetros o no, por ejemplo:
def saludar() -> str:
"""Función sin parámetros que retorna
una cadena de texto, simulando un saludo
"""
return "Hola"
def saludar_msj(msj) -> str:
"""Función con un parámetro que retorna
la cadena de texto que se ingresa"""
return msj
# Probamos nuestras funciones
print(saludar())
print()
print(saludar_msj("Hola, bienvenido"))
Hola Hola, bienvenido
Ahora, ¿qué pasa si no colocamos valores en los parámetros de una función definida con parámetros?
# Definamos una funcion que reciba dos parametros
def sumar(a, b) -> float:
"""Función de dos parámetros que retorna
la suma de a y b, es decir, retorna a+b"""
return a + b
# Primera prueba de la funcion
print(sumar(3.14, 5))
8.14
# Segunda prueba, omitiremos colocar un valor
# para un parametro
print(sumar(7))
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Input In [13], in <cell line: 3>() 1 # Segunda prueba, omitiremos colocar un valor 2 # para un parametro ----> 3 print(sumar(7)) TypeError: sumar() missing 1 required positional argument: 'b'
# o tambien
print(sumar(7,))
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Input In [14], in <cell line: 2>() 1 # o tambien ----> 2 print(sumar(7,)) TypeError: sumar() missing 1 required positional argument: 'b'
En ambos casos obtenemos un error. Ahora bien, dentro de Python podemos colocar valores por defecto a nuestros parámetros, para conseguir que la función actúe aún si nosotros omitimos colocar algún valor a alguno de los parámetros. Por ejemplo, asignaremos el valor de cero como valor por defecto a los parámetros a
y b
de la función anterior:
# valores por defecto
def sumar2(a = 0, b = 0) -> float:
"""Función de dos parámetros que retorna
la suma de a y b, es decir, retorna a+b"""
return a + b
# Pongamos a prueba nuestra funcion:
# No colocaremos ningun valor a los parametros
print(sumar2())
0
Donde el resultado arrojado es cero pues, por defecto, se efectúo la suma 0+0
correspondientes a los valores por defecto de los parámetros a
y b
. Otros caso:
# No colocaremos un segundo parametro
print(f"Resultado de sumar 4 + 0: {sumar2(4)}")
print()
print(f"El valor de a es de 9 y el de b es de cero: {sumar2(9,)}")
Resultado de sumar 4 + 0: 4 El valor de a es de 9 y el de b es de cero: 9
# Pero lo que no podemos hacer es omitir
# de la siguiente manera el primer parametro
print(f"El valor de a es de 0 y el de b es de 5: {sumar2(,5)}")
Input In [17] print(f"El valor de a es de 0 y el de b es de 5: {sumar2(,5)}") ^ SyntaxError: f-string: invalid syntax
De tal manera es como vemos la gran utilidad de colocar valores por defecto a los parámetros de nuestras funciones. Otro ejemplo:
def saludar_msj2(msj = "Bienvenido") -> str:
"""Función con un parámetro que retorna
la cadena de texto que se ingresa"""
return msj
# Ponemos a prueba nuestra funcion
# sin valor en el parametro
print(saludar_msj2())
print()
# Con valor en el parametro
print(saludar_msj2("Hola"))
Bienvenido Hola
Supongamos que queremos crear una función que calcule la suma de tres números:
def suma_tres(a=0, b=0, c=0) -> float:
"""Funcón que recibe tres parámetros
y retorna su suma"""
return a + b + c
Si queremos crear una función para calcular la suma de 4 números, tendremos entonces, por ejemplo, que definir una función de 4 parámetros. Ahora, algo más complicado, qué tal sino sabemos de manera específica el total de números que sumaremos, cómo implemenaremos entonces nuestra función sino sabemos cuántos parámetros configurar. Para ello está el concepto de parámetros variables.
Lo que podemos hacer con este tipo de parámetros es decirle a Python que no sabemos exactamente el número de parámetros a configurar en nuestra función, pero lo que sí sabemos es lo que haremos con ellos. Por ejemplo, queremos definir una función que sume todos los valores ingresados en los parámetros, pero en este caso el número de parámetros puede ser de dos (para sumar dos números), pueden ser tres (para sumar tres número), etcétera. Para ello utilizaremos parámetros variables para que el número de parámetros en nuestra función pueda ser de cualquier número (por ejemplo dos parámetros, tres, cuatro, etcétera), pero sin importar el número de parámetros, sumaremos los valores asignados a ellos. Con la idea anterior evitamos crear más de una función para poder sumar dos números ó tres ó más.
Para implementar parámetros variables colocaremos dentro de los paréntesis de nuestra función, el nombre que queremos asignarle a dicho parámetro. Luego, para especificar, justamente, que queremos que ese parámetro sea variable, colocaremos como prefijo un *
. Por ejemplo, crearemos una función para calcular la suma de cualquier cantidad de números:
# *valores: argumento variable
# puede representar 1, 2, 3, etcetera
# parametros
def sumas(*valores) -> float:
"""Función para calcular la suma de los
valores ingresados. Los parámetros son
variables y la función retorna el resultado
de sumarlos.
"""
# Almacenaremos en esta variable la suma
# correspondiente de cada uno de los
# valores ingresados en la funcion
resultado = 0
# Iteramos sobre los valores ingresados
# en la funcion:
for i in valores:
# vamos sumando dicho valores
# y el resultado quedara almacenado
# en la variable resultado
resultado += i
# Retornamos la suma de los valores ingresado
return resultado
# Probamos nuestra funcion:
print(f"Suma de 2 valores: {sumas(3,4)}")
print(f"Suma de 3 valores: {sumas(1,2,3)}")
print(f"Suma de 4 valores: {sumas(10, 40, 50, 4)}")
print(f"Suma de 8 valores: {sumas(1, 2, 3, 4, 5, 6, 7, 8)}")
Suma de 2 valores: 7 Suma de 3 valores: 6 Suma de 4 valores: 104 Suma de 8 valores: 36
Lo que ocurre es que Python creará una tupla con los valores ingresados en un parámetro variable. De tal manera, considerando sumas(10, 40, 50, 4)
, tenemos que Python creó implícitamente la tupla (10, 40, 50, 4)
a la que denominó valores
(justo como el nombre del parámetro variable). Es por ello que podemos iterar sobre el parámetro (tupla) valores
. Por ende, considerando la tupla generada por el parámetro variable, podemos acceder a sus elementos utilizando índices:
def sumas_recorrer(*valores) -> None:
"""Función de argumentos variables
que no retorna nada. Lo que hace esta función
es, en el proceso, imprimir todos los valores
ingresados en el parámetro variable
"""
# Recorremos todos los elementos de la tupla
# valores
for i in range(len(valores)):
print(f"Valor {i + 1} ingresado: {valores[i]}")
# Retorno (opcional)
return None
# Ponemos a prueba nuestra funcion
sumas_recorrer(10, 40, 50, 4)
print("-" * 30)
sumas_recorrer(1, 2, 3, 4, 5, 6, 7, 8)
Valor 1 ingresado: 10 Valor 2 ingresado: 40 Valor 3 ingresado: 50 Valor 4 ingresado: 4 ------------------------------ Valor 1 ingresado: 1 Valor 2 ingresado: 2 Valor 3 ingresado: 3 Valor 4 ingresado: 4 Valor 5 ingresado: 5 Valor 6 ingresado: 6 Valor 7 ingresado: 7 Valor 8 ingresado: 8
Otro ejemplo utilizando parámetros variables:
def mensaje_bienvenida(*alumnos) -> str:
"""Función de parámetros variables que retorna
una cadena de texto con un mensaje de saludo
para todos los alumnos ingresados en
la función."""
# Inicio del mensaje
msj = "Bienvenido: "
# Recorremos la tupla alumnos
for i in range(len(alumnos)):
# agregamos el alumno y una coma
if i != len(alumnos) - 1:
msj += alumnos[i] + ", "
# agregamos el ultimo alumno y
# agregamos un punto al final
else:
msj += alumnos[i] + "."
# retornamos el mensaje de bienvenida
return msj
# Probamos nuestra funcion
print(mensaje_bienvenida("Danna", "Pedro"))
print(mensaje_bienvenida("Danna", "Pedro", "Luis", "Carlos", "Carmen"))
Bienvenido: Danna, Pedro. Bienvenido: Danna, Pedro, Luis, Carlos, Carmen.
Ahora bien, así como los parámetros variables se convierten en tuplas dentro de nuestra función, podemos considerar tener parámetros del estilo key-value. Esto es, podemos tener parámetros variables que dentro de nuestra función se procesen (o se consideren) como un diccionario. Para ello colocaremos **
en vez de un simple *
, con lo cual conseguimos que **<nombre_parametro_variable>
se contemple como un diccionario, con la estructura que ya conocemos de key-value. Por ejemplo, crearemos una función de argumentos variables en la que ingresaremos el símbolo de un elemento (el cual será la key), seguido de su nombre (el cual será su value asociado), pero en este caso no utilizaremos la notación de diccionario que ya aprendimos Au: "oro", H: "Hidrógeno"
, en vez de ello escribiremos dentro del parámetro variable Au = "Oro", H = "Hidrógeno"
. Esto es:
def tabla_periodica(**elementos) -> None:
"""Función de argumentos variables que recibe
valores clave (keys) y sus valores correspondientes
(values) y no retorna nada. La función imprime cada una de
estas asociaciones key-value"""
# Iteramos sobre el diccionario elementos
for key, value in elementos.items():
print(f"{key} --> {value}")
# Ponemos a prueba nuestra funcion
# Se estara creando detras
# el diccionario {"Au": "Oro", "H": "Hidrógeno", "Mg": "Magnecio", "Ag": "Plata"}
tabla_periodica(Au = "Oro", H = "Hidrógeno", Mg = "Magnecio", Ag = "Plata")
Au --> Oro H --> Hidrógeno Mg --> Magnecio Ag --> Plata
Notemos que, tanto en las funciones con parámetros variables con un *
como con dos **
, si no pasamos valor alguno, no tendremos problema, esto es, no se nos marcará error:
# funcion con un parametro variable con un *
sumas_recorrer()
# funcion con un parametro variable con dos **
tabla_periodica()
Recordemos que toda función retorna un valor aunque no especifiquemos explícitamente ello. Cuando no incluimos el return
en la definición de una función, Python entiende que dicha función, en efecto, no regresa nada, pero para representar esta idea de la nada Python se vale de la cláusula None
. De tal manera, si no especificamos un retorno en una función, en automático o por defecto dicha función retorna en realidad el "valor" de None
. Por ejemplo
def mensaje(msj) -> None:
"""Función de un parámetro que no retorna nada.
Esta función manda a imprimir el mensaje ingresado
en el parámetro"""
print(msj)
# Ponemos a prueba nuestra funcion
mensaje("Hola")
Hola
Donde, recordemos, la función mensaje()
propiamente no retorna nada. De hecho, la idea de ver un resultado al ejecutar nuestras celdas de código, por ejemplo cuando utilizamos la función print()
, es muy distinto a producir o arrojar un resultado. Es decir, el hecho de que una función muestre algún resultado, es muy distinto a que dicha función produzca o arroje un resultado. Así, tanto la función que definimos mensaje()
como la función predefinida print()
no retornan o arrojan algún resultado. En particular, la función mensaje()
no retorna ningún resultado, donde, por defecto, implícitamente dicha función retornará el valor de None
.
Lo anterior lo podemos ver de una manera más visual si mandamos a imprimir el resultado de ejecutar la función mensaje()
, o en otras palabras, podemos mandar a imprimir el valor None
producido por la función mensaje()
:
print(mensaje("Hola"))
Hola None
Donde primero se ejecuta la instrucción print(msj)
configurada en la definición de la función, y después se imprime el valor que retorna dicha función, el cual es en este caso el valor de None
.
Por otro lado, hasta el momento hemos visto que nuestras funciones sólo retornan un valor, pero puede llegarse a presentar la necesidad de que una función retorne más de un valor. Lo anterior se puede implementar de una manera muy sencilla si en el return
colocamos los valores a retornar separados por comas. Por ejemplo
def sum_mult(*nums) -> tuple[float]:
"""Función de argumentos variables que retorna dos
valores:
- la suma de todos los números ingresados
- la multiplicación de todos los números ingresados"""
# Variables auxiliares para almacenar las sumas
# y las multiplicaciones
suma = 0
mult = 1
# Calculos
for i in nums:
suma += i
for i in nums:
mult *= i
# Retornamos dos valores
# -> float
# -> str
# dos valores
# -> ¿?
return suma, mult
# ponemos a prueba nuestra funcion
print(sum_mult(1, 2.2, 3, 4.0, 5))
(15.2, 132.0)
de donde:
Cuando nuestras funciones retornan más de un valor, Python agrupa de manera automática, dichos valores de retorno, dentro de una tupla en el orden que colocamos estos valores. Por ejemplo, de la función anterior, al declarar return suma, mult
se generará en automático la tupla (<suma>, <mult>)
. Por ende, al ejecutar print(sum_mult(1, 2.2, 3, 4.0, 5))
vemos que la salida es la tupla (15.2, 132.0)
, siendo el valor de la primer entrada correspondiente a la suma (suma
) de los parámetros ingresados y el valor de la segunda entrada correspondiente a la multiplicación (mult
) de los parámetros ingresados. En resumen, cuando retornemos más de un resultado, éstos se almacenarán en una tupla.
Una vez dicho lo anterior, tenemos entonces que sum_mult(<numeros>)
es una tupla, en este caso, de dos entradas o de longitud 2, donde la posición 0 corresponde a la suma de los números y la posición 2 a la multiplicación. Por ejemplo
print(f"Posición 0, suma de los números de los parámetros de la\
función sum_mult: {sum_mult(1, 2.2, 3, 4.0, 5)[0]}")
print()
print(f"Posición 1, multiplicación de los números de los \
parámetros de la función sum_mult: {sum_mult(1, 2.2, 3, 4.0, 5)[1]}")
Posición 0, suma de los números de los parámetros de lafunción sum_mult: 15.2 Posición 1, multiplicación de los números de los parámetros de la función sum_mult: 132.0
Continuando,
-> tuple[float]
: Nos dice que la función retorna una tupla (tuple
) cuyas entradas son números flotantes. Por ejemplo, si nuestra función retornara varios valores del tipo int
, entonces deberíamos colocar tuple[int]
; o también, si la función retorna varias cadenas de texto por separado, colocamos tuple[str]
. Recordemos que lo anterior es una buena práctica y opcional. Además, representa el tipo de salida esperada, pero también puede ocurrir que dicha función no regrese exactamente lo que se menciona con esta instrucción.En resumen, cuando colocamos varios valores de retorno para una función, por defecto se crea una tupla con dichos valores. Con base a lo anterior, tenemos que
# Podemos definir la funcion sum_mult de manera
# alternativa como:
def sum_mult(*nums) -> tuple[int]:
"""Función de argumentos variables que retorna dos
valores:
- la suma de todos los números ingresados
- la multiplicación de todos los números ingresados"""
suma = 0
mult = 1
for i in nums:
suma += i
for i in nums:
mult *= i
# Explicitamente declaramos la tupla
# de los valores a retornar:
return (suma, mult)
# ponemos a prueba nuestra funcion
print(sum_mult(1,2,3,4,5))
(15, 120)
Recordemos entonces que las funciones que retornan más de un valor, por defecto, retornan una tupla con dichos valores. Ahora bien, podemos también definir funciones que retornen listas, conjuntos, diccionarios, etcétera. Por ejemplo:
# Podemos definir la funcion sum_mult de manera
# alternativa, especificando en el retorno
# que el resultado de la funcion sera una lista.
# Configuramos el tipo de retorno esperado: list[float]
def sum_mult2(*nums) -> list[float]:
"""Función de argumentos variables que retorna dos
valores:
- la suma de todos los números ingresados
- la multiplicación de todos los números ingresados
Los cuales son agrupados en una lista
"""
suma = 0
mult = 1
for i in nums:
suma += i
for i in nums:
mult *= i
# Especificamente declaramos que el retorno
# es una lista:
return [suma, mult]
# ponemos a prueba nuestra funcion
print(f"Retorno de una lista: {sum_mult2(1, 2.2, 3, 4.5, 5)}")
Retorno de una lista: [15.7, 148.5]
# Retornaremos ahora un diccionario
def sum_mult3(*nums) -> dict[int]:
"""Función de argumentos variables que retorna dos
valores:
- la suma de todos los números ingresados
- la multiplicación de todos los números ingresados"""
suma = 0
mult = 1
for i in nums:
suma += i
for i in nums:
mult *= i
# Explicitamente declaramos que
# el retorno es un diccionario
return {"Suma": suma, "Multiplicación": mult}
# ponemos a prueba nuestra funcion
print(sum_mult3(1, 2, 3, 4, 5))
{'Suma': 15, 'Multiplicación': 120}