Curso de Python : Clase 2

Temas:

  • Tipos de datos nativos:
    • Listas y tuplas
    • Diccionarios
  • Iteraciones
  • Mutabilidad e inmutabilidad

Tipo de datos

  • Python cuenta con una gran variedad de tipos de datos que permiten representar la información según cómo esté estructurada.

  • Las tuplas y las listas son tipos de datos utilizados cuando se quiere agrupar elementos.

Tuplas

  • Es un agrupamiento de datos
  • Los datos pueden ser de distinto tipo
  • Las tuplas son inmutables, como las cadenas
In [4]:
una_fecha = (22, "Mayo", 2015)
otra_fecha = (14, "Junio", 1974)
fechas = (una_fecha, otra_fecha)

print type(una_fecha)
print type(otra_fecha)
print type(fechas)

print fechas
<type 'tuple'>
<type 'tuple'>
<type 'tuple'>
((22, 'Mayo', 2015), (14, 'Junio', 1974))

Elementos y segmentos de tuplas

  • Las tuplas son secuencias, igual que las cadenas, y se puede utilizar la misma notación de índices que en las cadenas para obtener cada una de sus componentes.

  • Todas las secuencias en Python comienzan a numerarse desde 0. Es por eso que se produce un error si se quiere acceder al n-ésimo elemento de un tupla

Tuplas inmutables

  • Al igual que con las cadenas, las componentes de las tuplas no pueden ser modificadas
In [5]:
t1 = (20, "Mayo", 1995)
t1[1] = "Junio"
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-5-7e16916c00c8> in <module>()
      1 t1 = (20, "Mayo", 1995)
----> 2 t1[1] = "Junio"

TypeError: 'tuple' object does not support item assignment

Longuitud de tuplas

  • A las tuplas también se les puede aplicar la función len() para calcular su longitud. El valor de esta función aplicada a una tupla nos indica cuántas componentes tiene esa tupla.
In [6]:
len(t1)
Out[6]:
3

Operaciones

  • Creación
In [7]:
unaTupla = (22, True, "una lista", (1, 2))
  • Suma (concatenación)
In [8]:
(1,2) + (3,4) + (5,6)
Out[8]:
(1, 2, 3, 4, 5, 6)
  • Multiplicación
In [9]:
(1,2) * 3
Out[9]:
(1, 2, 1, 2, 1, 2)
  • Obtener el largo
In [10]:
tupla = ("a", "b", "c")
len(tupla)
Out[10]:
3
  • Recorrer los elementos
In [11]:
unaTupla = (22, True, "una lista")
for elemento in unaTupla:
    print(elemento)
22
True
una lista
  • Acceder a una posición
    • Operador []
    • Slicing

Veamos algunos casos:

una_fecha = (22, "Mayo", 2015)
otra_fecha = (14, "Junio", 1974)
fechas = (unaFecha, otraFecha)
In [13]:
una_fecha[0]
Out[13]:
22
In [14]:
for elemento in otra_fecha:
    print elemento
14
Junio
1974
In [15]:
for fecha in fechas:
    print fecha
(22, 'Mayo', 2015)
(14, 'Junio', 1974)
In [17]:
tupla = (1,4,2)
print "El largo de la tupla es", len(tupla)
tupla[3] #BOOM!
El largo de la tupla es 3
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-17-d9ec06799779> in <module>()
      1 tupla = (1,4,2)
      2 print "El largo de la tupla es", len(tupla)
----> 3 tupla[3] #BOOM!

IndexError: tuple index out of range

Tupla vacía

In [18]:
t = ()
len(t)
Out[18]:
0

Tupla unitaria

  • Una tupla unitaria es una tupla con una componente.
In [19]:
u = (10)
len(u)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-19-3f6a7703a23f> in <module>()
      1 u = (10)
----> 2 len(u)

TypeError: object of type 'int' has no len()
  • Para distinguir la tupla unitaria de la componente que contiene, Python exige que a la componente no sólo se la encierre entre paréntesis sino que se le ponga una coma a continuación del valor de la componente (así (1810) es un número, pero(1810,) es la tupla unitaria cuya única componente vale 1810)
In [20]:
u = (10,)
len(u)
Out[20]:
1

Empaquetado

  • Si a una variable se le asigna una secuencia de valores separados por comas, el valor de esa variable será la tupla formada por todos los valores asignados. A esta operación se la denomina empaquetado de tuplas.
In [2]:
a = 125
b = "#"
c = 0.3
d = a,b,c

Desempaquetado

In [4]:
print len(d)
x,y,z = d
print x
print y
print z
3
125
#
0.3
In [5]:
#Si no son la misma cantidad de variables
p,q = d
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-5-da0483377863> in <module>()
      1 #Si no son la misma cantidad de variables
----> 2 p,q = d

ValueError: too many values to unpack

Devolver varios elementos

In [7]:
# Devuelve una tupla
def devuelve_varios_elementos():
    return 1, "b", ("tupla", "de", "cadenas")

devuelve_varios_elementos()
Out[7]:
(1, 'b', ('tupla', 'de', 'cadenas'))

Listas

  • En otros lenguajes son arrays o vectores
  • Colección ordenada
  • Pueden contener cualquier tipo de dato
  • Son mutables

Operaciones

  • Creación
In [9]:
unaLista = [22, True, "una lista", (1, 2)]
otraLista = [102]
otraLista
Out[9]:
[102]
  • Cuenta con las mismas operaciones que las tuplas y strings (son todas secuencias)

Operaciones de secuencias

Operación Resultado
x in s Indica si la variable x se encuentra en s
s+t Concantena las secuencias s y t.
s*n Concatena n copias de s.
s[i] Elemento i de s, empezando por 0.
s[i:j] Porción de la secuencia s desde i hasta j (no inclusive).
s[i:j:k] Porción de la secuencia s desde i hasta j (no inclusive), con paso k.
len(s) Cantidad de elementos de la secuencia s.
min(s) Mínimo elemento de la secuencia s.
max(s) Máximo elemento de la secuencia s.

Ejercicio 2.1

  • Escribir una función que reciba una tupla de elementos e indique si se encuentran ordenados de menor a mayor o no.

Solución 2.1

In [28]:
def esta_ordenada(secuencia):
    for i in range(len(secuencia) - 1):
        if secuencia[i] > secuencia[i+1]:
            return False
    return True
In [29]:
def esta_ordenada2(secuencia):
    elem_anterior = secuencia[0]
    for elem in secuencia:
        if elem_anterior > elem:
            return False
        elem_anterior = elem
    return True

Comentarios

  • Duck typing

    If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.

  • Late binding

 Ejercicio 2.2

  • Escribir una función sumatoria que reciba una función y una secuencia, y devuelva el resultado de sumar los valores de la secuencia luego de haberlos procesado

Solución 2.2

In [30]:
def sumatoria(funcion, secuencia):
    resultado = 0
    for x in secuencia:
        resultado += funcion(x)
    return resultado

Operaciones Listas

Las Listas son mutables

In [13]:
una_lista = ["Miguel", 21, "Mati", 21]
una_lista
Out[13]:
['Miguel', 21, 'Mati', 21]
In [14]:
una_lista[1]
Out[14]:
21
In [15]:
una_lista[1] = 22
print una_lista
una_lista[1]
['Miguel', 22, 'Mati', 21]
Out[15]:
22

Se pueden agregar elementos al final con append

In [34]:
una_lista
Out[34]:
['Miguel', 22, 'Mati', 21]
In [35]:
una_lista.append("Juan")
una_lista.append(23)
In [36]:
una_lista
Out[36]:
['Miguel', 22, 'Mati', 21, 'Juan', 23]

También se pueden agregar en una posición en particular con insert

In [37]:
una_lista = ["Miguel", 21, "Juan", 23]
una_lista.insert(2, "Mati")
una_lista
Out[37]:
['Miguel', 21, 'Mati', 'Juan', 23]
In [38]:
una_lista.insert(3, 21)
una_lista
Out[38]:
['Miguel', 21, 'Mati', 21, 'Juan', 23]

Remover un elemento con remove

In [39]:
una_lista = ["Miguel", 21, "Juan", 23]
una_lista.remove("Miguel")
una_lista.remove(21)
una_lista
Out[39]:
['Juan', 23]
In [40]:
#Si tratamos de eliminar un elemento inexistente
una_lista.remove("Pedro")
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-40-2973760bb27c> in <module>()
      1 #Si tratamos de eliminar un elemento inexistente
----> 2 una_lista.remove("Pedro")

ValueError: list.remove(x): x not in list

Podemos preguntar si una lista contiene un valor con la keyword in

In [41]:
"Pedro" in una_lista
Out[41]:
False
In [16]:
#Con esto podemos hacer cosas del estilo
def safe_remove(lista, valor):
    if valor in lista:
        lista.remove(valor)

safe_remove(una_lista, "Pedro")

Se puede conocer el indice de un elemento en una lista con index

In [47]:
una_lista = ["a", "hola", 23]
una_lista.index("hola")
Out[47]:
1
In [48]:
una_lista.index("chau")
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-48-c66b7ed38d6d> in <module>()
----> 1 una_lista.index("chau")

ValueError: 'chau' is not in list

Ejercicio 2.3

Dada una lista de números enteros, escribir una función que:

  • Devuelva una lista con todos los que sean pares.
  • Devuelva una lista con el cuadrado de cada uno de esos números.

Solución 2.3

In [50]:
def es_par(x):
        return x % 2 == 0

def cuadrado(x):
        return x*x

def my_filter(funcion, secuencia):
    resultado = []
    for elemento in secuencia:
        if funcion(elemento):
            resultado.append(elemento)
    return resultado

def my_map(funcion, secuencia):
    resultado = []
    for elemento in secuencia:
        resultado.append(funcion(elemento))
    return resultado

Se pueden ordenar los elementos de una lista con sorted

Devuelve una copia de la lista ordenada

In [18]:
lista = [4,6,2,1,9,7,8,3]
lista_ordenada = sorted(lista)
print lista
lista_ordenada
help(sorted)
[4, 6, 2, 1, 9, 7, 8, 3]
Help on built-in function sorted in module __builtin__:

sorted(...)
    sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list

También podemos ordenar una lista in-place con sort

La lista original nos queda modificada

In [52]:
lista2 = [2,5,3,4,2,3,4,1]
lista2.sort()
lista2
Out[52]:
[1, 2, 2, 3, 3, 4, 4, 5]

¿Y si tenemos elementos de diferente tipo?

In [23]:
lista3 = ["a",2,"chau",3,"hola",2,(2,2,3),4,3,(1,3,2),[1,3,2],[3,2,1]]
lista3.sort()
lista3
Out[23]:
[2,
 2,
 3,
 3,
 4,
 [1, 3, 2],
 [3, 2, 1],
 'a',
 'chau',
 'hola',
 (1, 3, 2),
 (2, 2, 3)]

Ejercicio 2.3.2

Escribir una función que reciba un texto y una longitud y devuelva una lista de cadenas de como máximo esa longitud. Las líneas deben ser cortadas correctamente en los espacios (sin cortar las palabras).

Ayuda:

cad = "hola como andas"
lista = cad.split(" ")
print lista

>>> ["hola", "como", "andas"]

Solución 2.3.2

In [24]:
def plegado(cadena, maxLen):
        resultado = []
        palabras = cadena.split()
        for palabra in palabras:
            if len(palabra) <= maxLen:
                resultado.append(palabra)
        return resultado

Diccionarios

  • Relacionan una clave y un valor
  • También llamados arreglos asociativos, matrices asociativas, o tablas de hash
  • No tienen orden
  • Las claves son únicas dentro de un diccionario
  • Como clave podemos utilizar cualquier valor inmutable

Operaciones con Diccionarios

Creación

In [39]:
dicc = {}
dicc = dict()

dicc = {"Uno":1, "Dos":2, "Tres":3}
dicc = dict([("Uno",1), ("Dos",2), ("Tres",3)])
dicc = dict(Uno=1, Dos=2, Tres=3)

#No tiene orden
dict(Uno=1, Dos=2, Tres=3)
Out[39]:
{'Dos': 2, 'Tres': 3, 'Uno': 1}

Agregar datos

In [40]:
dicc = {}
dicc["Lunes"] = 1
dicc["Martes"] = 2
dicc["Miercoles"] = 3

dicc
Out[40]:
{'Lunes': 1, 'Martes': 2, 'Miercoles': 3}

Acceder a datos

In [61]:
valor = dicc["Martes"]
print valor
2
In [62]:
#Si queremos acceder a un dato que no se encuentra en el diccionario
valor = dicc["Sabado"]
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-62-3eca073f2d9c> in <module>()
      1 #Si queremos acceder a un dato que no se encuentra en el diccionario
----> 2 valor = dicc["Sabado"]

KeyError: 'Sabado'
In [43]:
#Conviene utilizar get, si el dato no se encuentra devuelve None
valor = dicc.get("Sabado",0)
print valor
dicc["Sabado"] = dicc.get("Sabado",0) + 1
print dicc["Sabado"]
0
1

Modificar datos

Si se asigna un valor a una clave ya existente, se reemplaza el valor anterior

In [111]:
dicc = {"Lunes":1, "Martes":2, "Miercoles":3}
dicc["Martes"] = (2,3)
dicc
Out[111]:
{'Lunes': 1, 'Martes': (2, 3), 'Miercoles': 3}

Verificar si una clave se encuentra en un diccionario

No es posible preguntar por valores
In [102]:
"Lunes" in dicc
Out[102]:
True
In [103]:
"Domingo" in dicc
Out[103]:
False
In [104]:
if "Lunes" in dicc:
    print dicc["Lunes"]
1

Recorrer elementos

  • dicc.keys() : Devuelve una lista con las claves
  • dicc.values() : Devuelve una lista con los valores
  • dicc.items() : Devuelve una lista de tuplas de la forma (clave, valor)
  • dicc.iteritems()
In [115]:
dicc = {"Lunes":1, "Martes":2, "Miercoles":3}
dicc.keys()
Out[115]:
['Lunes', 'Miercoles', 'Martes']
In [116]:
dicc.values()
Out[116]:
[1, 3, 2]
In [48]:
dicc.items()
for clave_valor in dicc.itervalues():
    print clave_valor
1
1
3
2
In [68]:
#claves
print "Las claves son:"
for clave in dicc.keys():
    print clave

#valores
print "Los valores son:"
for valor in dicc.values():
    print valor

#items
for clave, valor in dicc.items():
    print clave, ":", valor
Las claves son:
Lunes
Miercoles
Martes
Los valores son:
1
3
2
Lunes : 1
Miercoles : 3
Martes : 2

Ejercicio 2.4

Escribir una función que cuente la cantidad de apariciones de cada caracter en una cadena de texto, y los devuelva en un diccionario.

Solución 2.4

In [7]:
def contar_letras(cadena):
    dicc = {}
    for letra in cadena:
        if letra in dicc:
            dicc[letra] += 1
        else:
            dicc[letra] = 1
    return dicc

contar_letras("Hola")
Out[7]:
{'H': 1, 'a': 1, 'l': 1, 'o': 1}
In [8]:
#Usando .get()
def contar_letras2(cadena):
    dicc = {}
    for letra in cadena:
        dicc[letra] = dicc.get(letra,0) + 1
    return dicc

contar_letras2("Hola")
Out[8]:
{'H': 1, 'a': 1, 'l': 1, 'o': 1}

Ejercicio 2.5

Escribir una función que reciba una lista de tuplas, y que devuelva un diccionario en donde las claves sean los primeros elementos de las tuplas, y los valores una lista con los segundos. Por ejemplo:

lista = [ (Hola, don Pepito), (Hola, don Jose), (Buenos, días) ]
print(tuplas_a_diccionario(lista))`

Deberá mostrar:

{ Hola: [don Pepito, don Jose], Buenos: [días] }

Ayuda:

dicc.get(clave,[]) # Me devuelve el valor de la clave en dicc o una lista vacía (si no existe la clave en el dicc)

Solución 2.5

In [84]:
def tuplas_a_dicc(tuplas):
    dicc = {}
    for tupla in tuplas:
        if tupla[0] in dicc:
            dicc[tupla[0]].append(tupla[1])
        else:
            dicc[tupla[0]] = [tupla[1]]
    return dicc


def tuplas_a_dicc(tuplas):
    dicc = {}
    for clave,valor in tuplas:
        dicc[clave] = dicc.get(clave, []) + [valor]
    return dicc
        

tuplas_a_dicc([ ("Hola", "don Pepito"), ("Hola", "don Jose"), ("Buenos", "dias") ])
Out[84]:
{'Buenos': ['dias'], 'Hola': ['don Pepito', 'don Jose']}

Sets

  • Colección desordenada sin elementos duplicados.
  • Buscan asemejarse a los conjuntos matemáticos.
  • Soportan operaciones de unión, intersección y diferencia.
  • Se los usa mayormente para probar pertenencia

Operaciones con sets

Creación y pertenencia
In [39]:
#Remueve los duplicados
canasta = {"pera", "naranja", "pera", "manzana", "naranja", "tomate"}
canasta
Out[39]:
{'manzana', 'naranja', 'pera', 'tomate'}
In [41]:
"naranja" in canasta
Out[41]:
True
In [42]:
"frutilla" in canasta
Out[42]:
False
In [67]:
a = set("abracadabra")
b = set("alacazam")
In [68]:
a
Out[68]:
{'a', 'b', 'c', 'd', 'r'}
In [69]:
b
Out[69]:
{'a', 'c', 'l', 'm', 'z'}
In [55]:
#Letra que están en 'a' y en 'b'
a&b
Out[55]:
{'a', 'c'}
In [56]:
#Letras que están en 'a' o en 'b'
a|b
Out[56]:
{'a', 'b', 'c', 'd', 'l', 'm', 'r', 'z'}
In [57]:
#Letras que están en 'a' pero no en 'b'
a-b
Out[57]:
{'b', 'd', 'r'}
In [58]:
#Letras que estan en 'a' o en 'b' (pero no en ambos)
a^b
Out[58]:
{'b', 'd', 'l', 'm', 'r', 'z'}

Técnicas para iterar

  • Claves y valores en un diccionario
In [70]:
dicc = {"Hola": "Juan", "Cómo": "te va?", "Muy": "Bien"}
for clave, valor in dicc.items():
    print clave, valor
Muy Bien
Cómo te va?
Hola Juan
In [70]:
preguntas = ["nombre", "edad", "color favorito"]
respuestas = ["Juan", "35", "azul"]
for pregunta, respuesta in zip(preguntas, respuestas):
    print("¿Cuál es tu " + pregunta + "? Es " + respuesta)
help(zip)
¿Cuál es tu nombre? Es Juan
¿Cuál es tu edad? Es 35
¿Cuál es tu color favorito? Es azul
Help on built-in function zip in module __builtin__:

zip(...)
    zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]
    
    Return a list of tuples, where each tuple contains the i-th element
    from each of the argument sequences.  The returned list is truncated
    in length to the length of the shortest argument sequence.

  • Índices en una lista
In [73]:
#enumerate() devuelve una lista de tuplas del tipo (indice, valor)

for i, v in enumerate(["tic", "tac", "toe"]):
    print (i,v)
    
lista = ["tic", "tac", "toe"]
print zip(range(len(lista)),lista)
print enumerate(lista)
(0, 'tic')
(1, 'tac')
(2, 'toe')
[(0, 'tic'), (1, 'tac'), (2, 'toe')]
<enumerate object at 0x1042eaaa0>

Mutabilidad

  • En Python todas las variables son referencias a memoria
  • Se debe tener cuidado al operar con estas variables
In [77]:
lista1 = ["Miguel", 37569522]
lista2 = lista1
lista3 = lista1[:]
lista2
Out[77]:
['Miguel', 37569522]
In [78]:
#lista2[1] = 38485934
lista3[1] = 123123123
#Que pasará con lista1?
In [79]:
print lista1
print lista2
print lista3
['Miguel', 37569522]
['Miguel', 37569522]
['Miguel', 123123123]

¿Que es mutable y que no?

Mutable Inmutable
Listas Strings
Diccionarios Números
Clases propias (por defecto) Booleanos
Tuplas

Para hacer una clase inmutable sobrecargamos los métodos set y delete, para que lancen una excepción

Parámetros

  • Si se modifica un parámetro para que apunte a otro valor, este cambio => NO se ve
  • Si se modifica el contenido de alguno de los parámetros mutables => SÍ se ve
  • En general, se espera que una función que recibe parámetros mutables no los modifique

Ejercicio 2.6

Realizar función que invierta la lista, pero en lugar de devolver una nueva, modifique la lista dada para invertirla, sin usar listas auxiliares.

Solución 2.6

In [76]:
def swap(lista, i, j):
    auxiliar = lista[i]
    lista[i] = lista[j]
    lista[j] = auxiliar

def invertir(lista):
    for i in range(len(lista) / 2):
        swap(lista, i, -(i + 1))


def invertir2(lista):
    lista.reverse()

Próxima Clase

  • Listas como pilas y colas
  • Listas por comprensión
  • Extensiones funcionales en Python
  • args + kwargs
  • Cadena con formato
  • Pruebas unitarias en Python