Saltar a contenido

4.Funciones, Tuplas, Diccionarios, Excepciones y Procesamiento de Datos

Funciones

Una función es un bloque de código que realiza una tarea especifica cuando la función es llamada (invocada). Las funciones son útiles para hacer que el código sea reutilizable, que este mejor organizado y más legible. Las funciones contienen parámetros y pueden devolver valores.

En general, las funciones se dividen en 4 tipos:

  • Varias funciones (como print()) son una parte integral de Python, y siempre están disponibles; se les llama a estas funciones integradas. Puede verse una lista en https://docs.python.org/3/library/functions.html

  • De los módulos preinstalados de Python.

  • Directamente del código, definidas por el usuario

  • Funciones lambda (aprenderemos sobre ellas en el curso Python 2)

Cuando usar funciones

Si un fragmento de código comienza a aparecer en más de una ocasión, considera la posibilidad de aislarlo en la forma de una función

Si un fragmento de código se hace tan extenso que leerlo o entenderlo se hace complicado, considera dividirlo en 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.

Definición de funciones

Las funciones propias se pueden definir utilizando la palabra reservada def y con la siguiente sintaxis:

def your_function(optional parameters):
    # el cuerpo de la función

Funciones parametrizadas

Se puede pasar información a las funciones utilizando parámetros. Las funciones pueden tener tantos parámetros como sean necesarios.

Los parámetros solo existen dentro de las funciones.

Los argumentos existen fuera de las funciones, y son los que pasan los valores a los parámetros correspondientes.

Sombreado

def message(number):
    print("Imprime un número:", number)

number = 1234
message(1)

print(number)

Paso de parámetros posicionales

def my_function(a, b, c):
    print(a, b, c)

my_function(1, 2, 3)

Paso de argumentos con palabra clave

def introduction(first_name, last_name):
    print("Hola, mi nombre es", first_name, last_name)

introduction(first_name = "James", last_name = "Bond")
introduction(last_name = "Skywalker", first_name = "Luke")

Combinar argumentos posicionales y de palabra clave

Primero se especifican los argumentos posicionales y después los de palabras clave

def adding(a, b, c):
    print(a, "+", b, "+", c, "=", a + b + c)

adding(1, 2, 3)

adding(c = 1, a = 2, b = 3)

adding(3, c = 1, b = 2)

Valores predefinidos

def introduction(first_name, last_name="González"):
    print("Hola, mi nombre es", first_name, last_name)

introduction(first_name="Guillermo")

# Hola, mi nombre es Guillermo González

return

Para que las funciones devuelvan un valor (pero no solo para ese propósito) se utiliza la instrucción return (regresar o retornar).

Nota: es una palabra clave reservada de Python.

La instrucción return tiene dos variantes diferentes: considerémoslas por separado

return sin una expresión

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.

def happy_new_year(wishes = True):
    print("Tres...")
    print("Dos...")
    print("Uno...")
    if not wishes:
        return

    print("¡Feliz año nuevo!")

None

None es ningún valor. Es una palabra 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.
value = None
if value is None:
    print("Lo siento, no contienes ningún valor")

Si una función no devuelve un cierto valor utilizando una cláusula de expresión return, se asume que devuelve implícitamente None.

Enviar una lista a una función como argumento

Cuando se envía una lista a una función, se envía una referencia a esa lista, por lo que cualquier modificación modifica la variable original:

list = [5, 4, 3]

def manipular_lista(lst):

    for i in range(0,len(lst)):
        lst[i] = "xxx"

    del lst[0]

manipular_lista(list)

print (list) # ahora vale ['xxx', 'xxx']

Devolver una lista como resultado de una función

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))

Alcance de un nombre

Es la parte del código donde el nombre es reconocido.

Una variable creada fuera de una función es visible dentro de una función. En otras palabras, el nombre de la variable se propaga dentro del cuerpo de la función. Esta variable no se puede modificar desde dentro de la función.

var = 11

def funcion():

    print("Variable var vale", var)

funcion()

Sin embargo en cuanto hacemos una asignación dentro de la función, se crea una variable nueva con el mismo nombre y de alcance limitado a la propia función.

var = 11

def funcion():
    var = 1 # Algo como var += 1 daría error
    print("Variable var vale", var) # Ahora var vale 1 y es una nueva variable.

funcion()

print(var) # Sigue valiendo 11

Una variable que existe fuera de una función tiene un alcance dentro del cuerpo de la función, excluyendo a aquellas que tienen el mismo nombre.

A una variable existente fuera de una función solo se puede acceder dentro de la función cuando su valor es leído. El asignar un valor hace que la función cree su propia variable.

global

Evita la duplicación de una variable dentro de una función, permitiendo que la variable sea modificada externamente también.

Podemos leer la variable de un ámbito superior sin problemas desde dentro de una función

a = 1

def leer():
    print (a)

leer() ## 1

Ahora bien, en el momento en que hacemos una asignación a la variable, se crea una copia en el ámbito de la función:

a = 1

def leer():
    print (a)

def modificar():
    # print (a) daría error si lo descomentamos ya que el interprete detecta la asignación de abajo
    a = 43 # creación de una nueva variable solo en el ambito de la función
    print (a)

leer() ## 1

modificar()

print (a) # 1

Para evitar este comportamiento y dejarnos modificar la variable del ámbito superior existe global que utilizado dentro de una función permite el acceso a la variable de ámbito superior.

x = "awesome"

def myfunc():
  global x # Posibilita modificar la variable de ámbito superior
  x = "fantastic"

myfunc()

print("Python is " + x) # "fantastic"

Algunas funciones simples

Factorial

Se expresa con un signo de exclamación, y es igual al producto de todos los números naturales previos al argumento o número dado.

\[0! = 1\]
\[1! = 1\]
\[2! = 1 * 2\]
\[3! = 1 * 2 * 3\]
\[4! = 1 * 2 * 3 * 4\]
\[:\]
\[:\]
\[n! = 1 * 2 ** 3 * 4 * ... * n-1 * n\]
def factorial_function(n):
    if n < 0:
        return None
    if n < 2:
        return 1

    product = 1
    for i in range(2, n + 1):
        product *= i
    return product


for n in range(1, 6):  # probando
    print(n, factorial_function(n))

Serie Fibonacci

Es una secuencia de números enteros:

\[a_{1}, a_{2}, a_{3},\cdots a_{n} \]

la cual sigue las siguientes reglas

  • El primer elemento de la secuencia es igual a uno (\(a_{1}=1\)).
  • El segundo elemento también es igual a uno (\(a_{2}=1\)).
  • Cada número después de ellos es la suma de los dos números anteriores

\(a_{n}=a_{n-1}+a_{n-2} \forall n \geqslant 2\)

def fib(n):
    if n < 1:
        return None
    if n < 3:
        return 1

    elem_1 = elem_2 = 1
    the_sum = 0
    for i in range(3, n + 1):
        the_sum = elem_1 + elem_2
        elem_1, elem_2 = elem_2, the_sum
    return the_sum


for n in range(1, 10):  # probando
    print(n, "->", fib(n))

Recursividad

En la programación computacional la recursividad es una técnica donde una función se invoca a si misma.

Tanto el factorial como la serie Fibonacci, son las mejores opciones para ilustrar este fenómeno.

La serie de Fibonacci es un claro ejemplo de recursividad:

\(a_{n}=a_{n-1}+a_{n-2} \forall n \geqslant 2\)

def fib(n):
    if n < 1:
        return None
    if n < 3:
        return 1
    return fib(n - 1) + fib(n - 2)

for n in range(1, 10):
    print(n, "->", fib(n))
def factorial_function(n):
    if n < 0:
        return None
    if n < 2:
        return 1
    return n * factorial_function(n - 1)


for n in range(1, 10):
    print(n, "->", factorial_function(n))

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.

Listas y Tuplas son objetos que contienen listas de datos a los que se accede mediante un índice, son similares a los arrays en otros lenguajes. Pertenecen a un tipo de datos que Python llama "Secuencias" y que incluye también a las cadenas de texto.

Todas las secuencias tienen algunas características comunes:

  • No hay un límite a la cantidad de elementos que pueden contener.
  • Pueden contener cualquier tipo de objeto, incluyendo otras secuencias. Por ejemplo, la forma de crear una matriz en Python es crear una lista de listas.
  • No es necesario saber el tamaño (cantidad de elementos) que tendrá la secuencia al momento de crearla.
  • Soportan algunas funciones nativas de python:
  • len(secuencia): devuelve la cantidad de elementos de la lista, tupla o cadena.
  • max(secuencia): devuelve el mayor elemento.
  • min(secuencia): devuelve el menor elemento.

  • Tienen dos métodos comunes:

  • secuencia.index(‘x’): devuelve el índice de la primera ocurrencia de ‘x’ en la secuencia.
  • secuencia.count(‘x’): devuelve el número de veces que aparece ‘x’ en la secuencia

  • Los elementos de la secuencia se acceden vía subíndices, que se indican entre corchetes [] después del nombre de la variable que contiene a la secuencia:

  • secuencia[0]: devuelve el primer elemento
  • secuencia[2]: devuelve el tercer elemento (notar que se numeran desde 0 y no desde 1).
  • secuencia[i]: devuelve el elemento i-1 de la secuencia.
  • secuencia[-1]: devuelve el último elemento.

Tuplas

Las tuplas son como las listas, excepto que son inmutables (sus elementos no pueden ser modificados). Se identifican fácilmente porque en vez de usar corchetes, se definen entre paréntesis. En lo demás, funcionan igual a las listas y al resto de las secuencias.

tuple_1 = (1, 2, 4, 8)
tuple_2 = 1., .5, .25, .125

También se puede crear una tupla utilizando la función integrada de Python tuple(). Esto es particularmente útil cuando se desea convertir un iterable (por ejemplo, una lista, rango, cadena, etcétera) en una tupla

my_list = [2, 4, 6]
print(my_list)    # salida: [2, 4, 6]
print(type(my_list))    # salida: <class 'list'>
tup = tuple(my_list)
print(tup)    # salida: (2, 4, 6)
print(type(tup))    # salida: <class 'tuple'>

De la misma manera, cuando se desea convertir un iterable en una lista, se puede emplear la función integrada de Python denominada list()

tup = 1, 2, 3, 
my_list = list(tup)
print(type(my_list))    # salida: <class 'list'>

Diccionarios

Un Diccionario es una estructura de datos y un tipo de dato en Python con características especiales que nos permite almacenar cualquier tipo de valor como enteros, cadenas, listas e incluso otras funciones. Estos diccionarios nos permiten además identificar cada elemento por una clave (Key).

Para definir un diccionario, se encierra el listado de valores entre llaves. Las parejas de clave y valor se separan con comas, y la clave y el valor se separan con dos puntos.

los diccionarios no son listas - no guardan el orden de sus datos, el orden no tiene significado (a diferencia de los diccionarios reales). El orden en que un diccionario almacena sus datos esta fuera de nuestro control.

Los diccionarios son colecciones indexadas de datos, mutables y desordenadas.

Info

Python 3.6 introdujo claves de diccionario ordenadas de forma predeterminada en la implementación de CPython.

Cada diccionario es un par de clave : valor.

my_dictionary = {
    key1: value1,
    key2: value2,
    key3: value3,
    }

Crear un diccionario

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.

dictionary = {"gato" : "chat", "perro" : "chien", "caballo" : "cheval"}
phone_numbers = {'jefe': 5551234567, 'Suzy': 22657854310}
empty_dictionary = {}

print(dictionary)
print(phone_numbers)
print(empty_dictionary)

Cuando escribes una expresión grande o larga, puede ser una buena idea mantenerla alineada verticalmente. Así es como puede hacer que el código sea más legible y más amigable para el programador, por ejemplo:

diccionario = {'nombre' : 'Juan',
               'edad' : 22,
               'cursos': ['Python','Django','JavaScript'] }

Este tipo de formato se llama sangría francesa.

Obtener valores

print(dictionary['gato'])
print(phone_numbers['Suzy'])

Nota

Si una clave es una cadena, se tiene que especificar como una cadena. Las claves son sensibles a las mayúsculas y minúsculas: 'Suzy' sería diferente a 'suzy'.

Atención

No se puede utilizar una clave que no exista

También puede utilizarse el método get()

item_2 = dictionary.get("gato")    # Ejemplo 2.

Método keys()

dictionary = {"gato" : "chat", "perro" : "chien", "caballo" : "cheval"}

for key in dictionary.keys():
    print(key, "->", dictionary[key])

# gato -> chat
# perro -> chien
# caballo -> cheval

La función sorted()

Ordenando por keys()

dictionary = {"gato" : "chat", "perro" : "chien", "caballo" : "cheval"}

for key in sorted(dictionary.keys()):
    print(key, "->", dictionary[key])

Métodos items() y values()

items() regresa una lista de tuplas donde cada tupla es un par de cada clave con su valor.

values() retorna una lista de los valores

dictionary = {"gato" : "chat", 
              "perro" : "chien", 
              "caballo" : "cheval"
              }

print(sorted(dictionary.items()))
print(sorted(dictionary.values()))
print(sorted(dictionary.keys()))

# [('caballo', 'cheval'), ('gato', 'chat'), ('perro', 'chien')]
# ['chat', 'cheval', 'chien']
# ['caballo', 'gato', 'perro']

Para comprobar si una clave existe en un diccionario, se puede emplear la palabra clave reservada in:

dictionary = {"gato" : "chat", 
              "perro" : "chien", 
              "caballo" : "cheval"
              }
if "perro" in dictionary:
  print("si")

Modificar, agregar y borrar valores de un diccionario

Los diccionarios son completamente mutables, no existen obstáculos para modificarlos.

dictionary = {"gato" : "chat", 
              "perro" : "chien", 
              "caballo" : "cheval"
              }

print(sorted(dictionary.items()))

dictionary['gato'] = 'miau'

print(sorted(dictionary.items()))

# [('caballo', 'cheval'), ('gato', 'chat'), ('perro', 'chien')]
# [('caballo', 'cheval'), ('gato', 'miau'), ('perro', 'chien')]

Solo se tiene que asignar un valor a una nueva clave que no haya existido antes y se creará dicha clave.

dictionary['pájaro'] = 'oiseau'

también se puede utilizar el método update()

dictionary = {"gato" : "chat", "perro" : "chien", "caballo" : "cheval"}

dictionary.update({"pato": "canard"})
print(dictionary)

Para eliminar una clave utilizamos la instrucción del:

del dictionary['pato']

Warning

El eliminar una clave no existente, provocará un error.

Para eliminar todos los elementos de un diccionario se debe emplear el método clear():

dictionary.clear()

Para copiar un diccionario emplea el método copy()

Gestión de excepciones

try except

try:
    value = input('Escribe un número natural: ')
    print('El recíproco de', value, 'es', 1/int(value))        
except:
    print('No se que hacer con', value)
try:
    value = input('Escribe un número natural: ')
    print('El recíproco de', value, 'es', 1/int(value))        
except ValueError:
    print('No se que hacer con', value)    
except ZeroDivisionError:
    print('La división entre cero no está permitida en nuestro Universo.')  
try:
    value = input('Escribe un número natural: ')
    print('El recíproco de', value, 'es', 1/int(value))        
except ValueError:
    print('No se que hacer con', value)    
except ZeroDivisionError:
    print('La división entre cero no está permitida en nuestro Universo.')    
except: # excepción por defecto (siempre la última)
    print('Ha sucedido algo extraño, ¡lo siento!')
while True:
    try:
        number = int(input("Escribe un número entero: "))
        print(5/number)
        break
    except (ValueError, ZeroDivisionError):
        print("Valor incorrecto o división entre cero.")
    except:
        print("Lo siento, algo salió mal...")

Capturar cualquier tipo de excepción y mostrar el mensaje de error:

def convertir_entero(valor):
    try:
        numero = int(valor)
        return numero
    except Exception as e:
        print("Ocurrió un error") 
        print("Error: ",e)
        return None

def main():
    convertir_entero("0a")

if __name__ == "__main__":
    main()

Excepciones útiles

ZeroDivisionError

ValueError

TypeError

AttributeError

SyntaxError

https://docs.python.org/3/library/exceptions.html

Recetas

Nombrar los elementos de una tupla a través de namedtuple

from collections import namedtuple

producto = ('Mouse',35)

print (producto[0])
print (producto[1])

Producto = namedtuple('Producto',['nombre','precio'])

producto_1 = Producto('Mouse',35)

print('---------')

print(producto_1.nombre)
print(producto_1.precio)

producto_2 = Producto(nombre='Mouse', precio=35)

nombre,precio = producto_2

print('')

print(producto_2.nombre)
print(producto_2.precio)

Crear variables independientes para cada elemento de una secuencia

tupla = (1,2)
a,b = tupla
print(a,b)

lista = ['Python',3,(2,3,),'P']
a,b,c,d = lista
print(a,b,c,d)

Obtener el resto de elementos de una secuencia

tupla = (1,2,5,7)
a,b, *c = tupla
print(a,b,c)

1 2 [5, 7]

lenguaje = 'Python'
var1,var2,*var3 = lenguaje
print(var1, var2, var3)

Diccionario con orden mediante la clase OrderedDict

from collections import OrderedDict

productos = {7:'Mouse', 5:'Teclado',8:'Monitor', 9:'Altavoces',2:'Cable corriente'}

print (OrderedDict(sorted(productos.items(), key=lambda p: p[0]))) # Ordenado por ID
print (OrderedDict(sorted(productos.items(), key=lambda p: p[1]))) # Ordenado por Nombre
print (OrderedDict(sorted(productos.items(), key=lambda p: len(p[1])))) # Ordenado por len(nombre)

OrderedDict([(2, 'Cable corriente'), (5, 'Teclado'), (7, 'Mouse'), (8, 'Monitor'), (9, 'Altavoces')])
OrderedDict([(9, 'Altavoces'), (2, 'Cable corriente'), (8, 'Monitor'), (7, 'Mouse'), (5, 'Teclado')])
OrderedDict([(7, 'Mouse'), (5, 'Teclado'), (8, 'Monitor'), (9, 'Altavoces'), (2, 'Cable corriente')])

Extraer un subconjunto de elementos de un diccionario

productos = {
    'Mouse':35,
    'Teclado':75,
    'Altavoz':55,
    'Monitor':335,
    'Tablet':435
}

productos_filtrados = {k:v for k, v in productos.items() if v > 50}

print (productos)
print (productos_filtrados)

{'Mouse': 35, 'Teclado': 75, 'Altavoz': 55, 'Monitor': 335, 'Tablet': 435}
{'Teclado': 75, 'Altavoz': 55, 'Monitor': 335, 'Tablet': 435}

Uso de la clase UserString

Esta clase se encuentra en el módulo Collections y se utiliza para realizar herencia cuando queremos agregar nuevos comportamientos a la clase string.

from collections import UserString

class StringPersonalizado (UserString):

    def invertir_capitalizacion(self):
        nueva_cadena = []

        for c in self:
            nueva_cadena.append(c.lower() if c.isupper() else c.upper())

        return ''.join(str(c) for c in nueva_cadena)

cadena = StringPersonalizado('Python')

print (cadena.invertir_capitalizacion())

pYTHON

[3 - Daniela, 5 - Juan, 7 - Eduardo, 10 - Silvia] [3 - Daniela, 7 - Eduardo, 5 - Juan, 10 - Silvia]

### Extraer un subconjunto de elementos de un diccionario

```python
productos = {
    'Mouse':35,
    'Teclado':75,
    'Altavoz':55,
    'Monitor':335,
    'Tablet':435
}

productos_filtrados = {k:v for k, v in productos.items() if v > 50}

print (productos)
print (productos_filtrados)

{'Mouse': 35, 'Teclado': 75, 'Altavoz': 55, 'Monitor': 335, 'Tablet': 435}
{'Teclado': 75, 'Altavoz': 55, 'Monitor': 335, 'Tablet': 435}

Última actualización: 2022-10-30