MÓDULO 4
Funciones, Tuplas, Diccionarios y Procesamiento de Datos
¿Qué aprenderás en este módulo?
1. Funciones.
2. Tuplas y Diccionarios.
Descarga el archivo para seguir la clase en Jupyter:
Descargar Archivo1. Funciones
¿Para qué utilizar funciones?
Hasta ahora solo se han invocado funciones para utilizarlas como herramientas, con el fin de hacer la vida más fácil, y para simplificar tareas tediosas y repetitivas.
Cuando se desea mostrar o imprimir algo en consola se utiliza print(). Cuando se desea leer el valor de una variable se emplea input(), combinados posiblemente con int() o float().
También se ha hecho uso de algunos métodos, los cuales también son funciones, pero declarados de una manera muy específica.
Un buen desarrollador divide el código (o mejor dicho: el problema) en piezas aisladas, y codifica cada una de ellas en la forma de una función.
Esto simplifica considerablemente el trabajo del programa, debido a que cada pieza se codifica por separado y consecuentemente se prueba por separado. A este proceso se le llama comúnmente descomposición.
Existe una segunda condición: si un fragmento de código se hace tan extenso que leerlo o entenderlo se hace complicado, considera dividirlo pequeños problemas por separado e implementa cada uno de ellos como una función independiente.
Esta descomposición continúa hasta que se obtiene un conjunto de funciones cortas, fáciles de comprender y probar.
Primer función
Así es como se ve la definición más simple de una función:
def function_name():
function_body
→ Siempre comienza con la palabra reservada def (que significa definir).
→ Después de def va el nombre de la función (las reglas para darle nombre a las funciones son las mismas que para las variables).
→ Después del nombre de la función, hay un espacio para un par de paréntesis (ahorita no contienen algo, pero eso cambiará pronto).
→ La línea debe de terminar con dos puntos.
→ La línea inmediatamente después de def marca el comienzo del cuerpo de la función - donde varias o (al menos una) instrucción anidada será ejecutada cada vez que la función sea invocada; nota: la función termina donde el anidamiento termina.
A continuación se definirá la función. Se llamará mensaje:
def mensaje():
print("Ingresa un valor: ")
# invocamos la función:
mensaje()
Ingresa un valor:
El proceso de ejecución de la función es el siguiente:
→ Cuando se invoca una función, Python recuerda el lugar donde esto ocurre y salta hacia dentro de la función invocada.
→ El cuerpo de la función es entonces ejecutado.
→ Al llegar al final de la función, Python regresa al lugar inmediato después de donde ocurrió la invocación.
Existen dos consideraciones muy importantes:
1. No se debe invocar una función antes de que se haya definido.
2. Una función y una variable no pueden compartir el mismo nombre.
Afortunadamente, es posible combinar o mezclar el código con las funciones - no es forzoso colocar todas las funciones al inicio del archivo fuente.
def mensaje():
print("Ingresa un valor: ")
mensaje()
a = int(input())
mensaje()
b = int(input())
mensaje()
c = int(input())
Ingresa un valor:
4
Ingresa un valor:
5
Ingresa un valor:
6
Funciones parametrizadas
Un parámetro es una variable, pero existen dos factores que hacen a un parámetro diferente:
Los parámetros solo existen dentro de las funciones en donde han sido definidos, y el único lugar donde un parámetro puede ser definido es entre los paréntesis después del nombre de la función, donde se encuentra la palabra reservada def.
La asignación de un valor a un parámetro de una función se hace en el momento en que la función se manda llamar o se invoca, especificando el argumento correspondiente.
def function(parameter):
###
Esta definición especifica que nuestra función opera con un solo parámetro con el nombre de number. Se puede utilizar como una variable normal, pero solo dentro de la función - no es visible en otro lugar.
Notas importante:
→ Los parámetros solo existen dentro de las funciones (este es su entorno natural).
→ Los argumentos existen fuera de las funciones, y son los que pasan los valores a los parámetros correspondientes.
Tomando en cuenta nuestro ejemplo anterior, vamos a agregar un parámetro:
def mensaje(number):
print("Ingresa un número:", number)
Ahora vamos a invocar la función asignando al parámetro un valor:
mensaje(5)
Obtendremos el siguiente resultado:
Ingresa un número: 5
Funciones parametrizadas (con dos parámetros)
Una función puede tener tantos parámetros como se desee.
Modifiquemos nuestra función:
def mensaje(what, number):
print("Ingresa", what, "número", number)
Invocamos la función y asignamos valor a los dos parámetros:
mensaje("precio", 55)
Observa el resultado:
Ingresa precio número 55
Paso de parámetros posicionales
La técnica que asigna cada argumento al parámetro correspondiente, es llamada paso de parámetros posicionales, los argumentos pasados de esta manera son llamados argumentos posicionales.
def my_function(a, b, c):
print(a, b, c)
my_function(1, 2, 3)
1 2 3
Paso de argumentos con palabras clave
Python ofrece otra manera de pasar argumentos, donde el significado del argumento está definido por su nombre, no su posición, a esto se le denomina paso de argumentos con palabra clave.
def introduction(first_name, last_name):
print("Hola, mi nombre es", first_name, last_name)
introduction(first_name = "Jaime", last_name = "Suárez")
introduction(last_name = "Rodríguez", first_name = "José")
Hola, mi nombre es Jaime Suárez
Hola, mi nombre es José Rodríguez
El concepto es claro: los valores pasados a los parámetros son precedidos por el nombre del parámetro al que se le va a pasar el valor, seguido por el signo de =.
La posición no es relevante aquí, cada argumento conoce su destino con base en el nombre utilizado.
Combinar argumentos posicionales y de palabras clave
Es posible combinar ambos tipos si se desea, solo hay una regla inquebrantable: se deben colocar primero los argumentos posicionales y después los de palabra clave.
Revisemos el siguiente ejemplo con tres parámetros:
def adding(a, b, c):
print(a, "+", b, "+", c, "=", a + b + c)
Su propósito es el de evaluar y presentar la suma de todos sus argumentos. Por lo tanto, la función al ser invocada de la siguiente manera:
adding(1, 2, 3)
Se tendrá como resultado:
1 + 2 + 3 = 6
A este punto es un ejemplo solo de argumentos posicionales.
También, se puede reemplazar la invocación actual por una con palabras clave, como la siguiente:
adding(c = 1, a = 2, b = 3)
El programa dará como salida lo siguiente:
2 + 3 + 1 = 6
Ahora intentemos mezclar ambas formas. Observa la siguiente invocación de la función:
adding(3, c = 1, b = 2)
Esto es lo que se verá como resultado:
3 + 2 + 1 = 6
Valores predefinidos
En ocasiones ocurre que algunos valores de ciertos argumentos son más utilizados que otros. Dichos argumentos tienen valores predefinidos los cuales pueden ser considerados cuando los argumentos correspondientes han sido omitidos.
Revisemos el siguiente ejemplo:
def introduction(first_name, last_name="González"):
print("Hola, mi nombre es", first_name, last_name)
Incovamos la función:
introduction(first_name = "Jorge")
Observamos el resultado:
Hola, mi nombre es Jorge Ramírez
Sin embargo, también podemos invocar la función ingresando nuevos valores a ambos parámetros en nuestro ejemplo:
introduction("Jorge", "Pérez")
Hola, mi nombre es Jorge Pérez
También podríamos invocar la función de la siguiente manera:
introduction("Enrique")
Observemos el resultado:
Hola, mi nombre es Enrique Ramírez
La instrucción return
Las funciones, al igual que las funciones matemáticas, pueden tener resultados. Para lograr que las funciones devuelvan un valor (pero no solo para ese propósito) se utiliza la instrucción return (regresar o retornar). Recuerda que es una palabra clave reservada también.
La instrucción return tiene dos variantes diferentes:
→ return sin una expresión.
→ return con una expresión.
return sin una expresión
La primera consiste en la palabra reservada en sí, sin nada que la siga.
Cuando se emplea dentro de una función, provoca la terminación inmediata de la ejecución de la función, y un retorno instantáneo (de ahí el nombre) al punto de invocación.
Nota: si una función no está destinada a producir un resultado, emplear la instrucción return no es obligatorio, se ejecutará implícitamente al final de la función.
De cualquier manera, se puede emplear para terminar las actividades de una función, antes de que el control llegue a la última línea de la función.
Revisemos el siguiente ejemplo:
def happy_new_year(wishes = True):
print("Tres...")
print("Dos...")
print("Uno...")
if not wishes:
return
print("¡Feliz año nuevo!")
Invocamos la función sin ningún argumento:
happy_new_year()
Tres...
Dos...
Uno...
¡Feliz año nuevo!
Ahora invoquemos la función con el argumento False:
happy_new_year(False)
Tres...
Dos...
Uno...
Se modificará el comportamiento de la función; la instrucción return provocará su terminación justo antes de los deseos.
return con una expresión
La segunda variante de return está extendida con una expresión:
def function():
return expression
Existen dos consecuencias de usarla:
→ Provoca la terminación inmediata de la ejecución de la función.
→ La función evaluará el valor de la expresión y lo devolverá (de ahí el nombre una vez más) como el resultado de la función.
Observa este sencillo ejemplo:
def x_function():
return 123
y = x_function()
print("Función x_function ha devuelto su resultado:", y)
Función x_function ha devuelto su resultado: 123
La instrucción return, enriquecida con la expresión (la expresión es muy simple aquí), "transporta" el valor de la expresión al lugar donde se ha invocado la función.
El resultado se puede usar libremente aquí, por ejemplo, para ser asignado a una variable.
Nota: También puede ignorarse por completo y perderse sin dejar rastro.
None
None no es un valor en lo absoluto; por lo tanto, no debe participar en ninguna expresión. Es una palabra clave reservada.
Solo existen dos tipos de circunstancias en las que None se puede usar de manera segura:
→ Cuando se le asigna a una variable (o se devuelve como el resultado de una función).
→ Cuando se compara con una variable para diagnosticar su estado interno.
Ejemplo:
value = None
if value is None:
print("No contienes ningún valor")
No contienes ningún valor
No olvides esto: si una función no devuelve un cierto valor utilizando una cláusula de expresión return, se asume que devuelve implícitamente None.
Ejemplo: la función strangeFunction retorna True cuando su argumento es par.
¿Qué es lo que retorna de otra manera?
def strange_function(n):
if(n % 2 == 0):
return True
Invocamos la función con dos valores distintos:
print(strange_function(2))
print(strange_function(1))
True
None
Listas y funciones
¿Se puede enviar una lista a una función como un argumento?
Si pasas una lista a una función, la función tiene que manejarla como una lista. Veámos el siguiente ejemplo:
def list_sum(lst):
s = 0
for elem in lst:
s += elem
return s
Invocamos la función:
print(list_sum([5, 4, 3]))
12
Ten en cuenta que debido a la naturaleza de la función anterior, no podríamos invocarla de la sigueinte manera:
print(list_sum(5))
Esto se debe al hecho de que el bucle for no puede iterar un solo valor entero.
TypeError: 'int' object is not iterable
¿Puede una lista ser el resultado de una función?
Cualquier entidad reconocible por Python puede ser un resultado de función.
Observa el siguiente código ejemplo:
def strange_list_fun(n):
strange_list = []
for i in range(0, n):
strange_list.insert(0, i)
return strange_list
print(strange_list_fun(5))
[4, 3, 2, 1, 0]
Las funciones y sus alcances
El alcance de un nombre (por ejemplo, el nombre de una variable) es la parte del código donde el nombre es reconocido correctamente.
El alcance del parámetro de una función es la función en sí. El parámetro es inaccesible fuera de la función.
Observa el siguiente código (al ejecutarlo ocurrirá un error):
def scope_test():
x = 123
scope_test()
print(x)
NameError: name 'x' is not defined
La palabra clave reservada global
¿Una función es capaz de modificar una variable que fue definida fuera de ella? La respuesta es no.
Sin embargo, existe un método especial el cual puede extender el alcance de una variable incluyendo el cuerpo de las funciones para poder no solo leer los valores de las variables sino también modificarlos, utilizando la palabra clave reservada global.
global name
global name1, name2, ...
Este nombre se convierte en global (tiene un alcance global, y no importa si se esta leyendo o asignando un valor).
def my_function():
global var
var = 2
print("¿Conozco a aquella variable?", var)
var = 1
my_function()
print(var)
¿Conozco a aquella variable? 2
2
2. Tuplas y Diccionarios.
Secuencia y mutabilidad
Secuencias
Un tipo de secuencia es un tipo de dato en Python el cual es capaz de almacenar más de un valor (o ninguno si la secuencia esta vacía), los cuales pueden ser secuencialmente (de ahí el nombre) examinados, elemento por elemento.
Debido a que el bucle for es una herramienta especialmente diseñada para iterar a través de las secuencias, podemos definirlas de la siguiente manera: una secuencia es un tipo de dato que puede ser escaneado por el bucle for.
La lista es un clásico ejemplo de una secuencia de Python.
Mutabilidad
La mutabilidad es una propiedad de cualquier tipo de dato en Python que describe su disponibilidad para poder cambiar libremente durante la ejecución de un programa. Existen dos tipos de datos en Python: mutables e inmutables.
Los datos mutables pueden ser actualizados libremente en cualquier momento, a esta operación se le denomina "in situ".
In situ es una expresión en Latín que se traduce literalmente como en posición, en el lugar o momento.
La siguiente instrucción modifica los datos "in situ":
list.append(1)
Los datos inmutables no pueden ser modificados de esta manera.
Tuplas
Una tupla es una secuencia inmutable. Se puede comportar como una lista pero no puede ser modificada en el momento.
Lo primero que distingue una lista de una tupla es la sintaxis. Las tuplas utilizan paréntesis, mientras que las listas usan corchetes, aunque también es posible crear una tupla tan solo separando los valores por comas.
tuple_1 = (1, 2, 4, 8)
tuple_2 = 1., .5, .25, .125
print(tuple_1)
print(tuple_2)
(1, 2, 4, 8)
(1.0, 0.5, 0.25, 0.125)
Recuerda algo muy importante: cada elemento de una tupla puede ser de distinto tipo (punto flotante, entero, cadena, o cualquier otro tipo de dato).
Crear una tupla
Vamos a crear una tupla vacía solo se necesitan unos paréntesis:
empty_tuple = ()
Para crear una tupla de un solo elemento, se debe de considerar que, debido a la sintaxis (una tupla debe de poder distinguirse de un valor entero ordinario), y colocar una coma al final:
one_element_tuple_1 = (1, )
one_element_tuple_2 = 1.,
Nota importante: El quitar las comas no arruinará el programa en el sentido sintáctico, pero serán dos variables, no tuplas.
Si deseas leer los elementos de una tupla, lo puedes hacer de la misma manera que se hace con las listas.
my_tuple = (1, 10, 100, 1000)
print(my_tuple[0])
print(my_tuple[-1])
print(my_tuple[1:])
print(my_tuple[:-2])
for elem in my_tuple:
print(elem)
1
1000
(10, 100, 1000)
(1, 10)
1
10
100
1000
Poero por otro lado, no intentes modificar el contenido de la tupla:
my_tuple = (1, 10, 100, 1000)
my_tuple.append(10000)
del my_tuple[0]
my_tuple[1] = -10
AttributeError: 'tuple' object has no attribute 'append'
Veamos algunas otros usos de las Tuplas:
my_tuple = (1, 10, 100)
t1 = my_tuple + (1000, 10000)
t2 = my_tuple * 3
print(len(t2))
print(t1)
print(t2)
print(10 in my_tuple)
print(-10 not in my_tuple)
9
(1, 10, 100, 1000, 10000)
(1, 10, 100, 1, 10, 100, 1, 10, 100)
True
True
Diccionarios
El diccionario es otro tipo de estructura de datos de Python. No es una secuencia (pero puede adaptarse fácilmente a un procesamiento secuencial) y además es mutable.
La palabra que se esta buscando se denomina clave(key). La palabra que se obtiene del diccionario es denominada valor. Esto significa que un diccionario es un conjunto de pares de claves y valores.
→ Cada clave debe de ser única. No es posible tener una clave duplicada.
→ Una clave puede ser un tipo de dato de cualquier tipo: puede ser un número (entero o flotante), o incluso una cadena.
→ Un diccionario no es una lista. Una lista contiene un conjunto de valores numerados, mientras que un diccionario almacena pares de valores.
→ La función len() aplica también para los diccionarios, regresa la cantidad de pares (clave-valor) en el diccionario.
→ Un diccionario es una herramienta de un solo sentido. Si fuese un diccionario español-francés, podríamos buscar en español para encontrar su contraparte en francés más no viceversa.
La lista de todos los pares es encerrada con llaves, mientras que los pares son separados por comas, y las claves y valores por dos puntos.
Utiliza la siguiente sintaxis para crear un diccionario. Observa el siguiente ejemplo:
dictionary = {"gato" : "plim", "perro" : "Ross"}
phone_numbers = {'jefe': 5551234567, 'Suzy': 22657854310}
empty_dictionary = {}
print(dictionary)
print(phone_numbers)
print(empty_dictionary)
{'gato': 'plim', 'perro': 'Ross'}
{'jefe': 5551234567, 'Suzy': 22657854310}
{}
En este primer ejemplo, el diccionario emplea claves y valores las cuales ambas son cadenas. En el segundo, las claves con cadenas pero los valores son enteros. El orden inverso (claves → números, valores → cadenas) también es posible, así como la combinación número a número.
Recordemos que los diccionarios no son listas - no guardan el orden de sus datos, el orden no tiene significado.
Si deseas obtener cualquiera de los valores, debes de proporcionar una clave válida:
print(dictionary['gato'])
print(phone_numbers['Suzy'])
chat
22657854310
El obtener el valor de un diccionario es semejante a la indexación, gracias a los corchetes alrededor del valor de la clave.
→ Si una clave es una cadena, se tiene que especificar como una cadena.
→ Las claves son sensibles a las mayúsculas y minúsculas.
El método keys()
Recordemos que un diccionario no es un tipo de dato secuencial - el bucle for no es útil aquí.
Sin embargo, existen herramientas simples y muy efectivas que pueden adaptar cualquier diccionario a los requerimientos del bucle for.
Revisemos un método denominado keys(), el cual es parte de todo diccionario. El método retorna o regresa una lista de todas las claves dentro del diccionario. Al tener una lista de claves se puede acceder a todo el diccionario de una manera fácil y útil.
Veámos el siguiente ejemplo:
dictionary = {"gato" : "plim", "perro" : "Ross",
"caballo" : "cheval"}
for key in dictionary.keys():
print(key, "->", dictionary[key])
gato -> plim
perro -> Ross
caballo -> cheval
El método items()
Otra manera de hacerlo es utilizar el método items(). Este método regresa una lista de tuplas donde cada tupla es un par de cada clave con su valor.
dictionary = {"gato" : "chat", "perro" : "chien",
"caballo" : "cheval"}
for spanish, french in dictionary.items():
print(spanish, "->", french)
gato -> chat
perro -> chien
caballo -> cheval
El método values()
También existe un método denominado values(), funciona de manera muy similar al de keys(), pero regresa una lista de valores.
dictionary = {"gato" : "chat", "perro" : "chien",
"caballo" : "cheval"}
for french in dictionary.values():
print(french)
chat
chien
cheval
Modificar, agregar y eliminar valores
Ejemplo 1: modificar valores en un diccionario.
dictionary = {"gato" : "perro", "dog" : "chien",
"caballo" : "cheval"}
dictionary['gato'] = 'minou'
print(dictionary)
{'gato': 'minou', 'dog': 'chien', 'caballo': 'cheval'}
Ejemplo 2: agregando nuevas claves.
dictionary = {"gato" : "chat", "perro" : "chien",
"caballo" : "cheval"}
dictionary['cisne'] = 'cygne'
print(dictionary)
{'gato': 'chat', 'perro': 'chien', 'caballo': 'cheval', 'cisne': 'cygne'}