El comportamiento de una pila se puede describir con la frase "Lo último que se apiló es lo primero que se usa". Es decir, su estructura es LIFO (Last in, First out)
Podríamos pensar en una pila de platos de donde se puede sacar el primer plato para lavar, pero no los del medio.
True
si la pila está vacía¿Como podríamos utilizar las operaciones de una lista para representar una pila?
Si tomamos la convención de que el tope de la pila se encuentra al final de la lista tenemos:
stack = []
stack
[]
append()
de las listas para agregar al finalstack.append(1)
stack.append(2)
stack.append(3)
stack.append(4)
stack
[1, 2, 3, 4]
pop()
de las listas para eliminar el ultimo elementostack.pop()
4
stack
[1, 2, 3]
def esta_vacia(pila):
return len(pila) is 0
def esta_vacia(pila):
return not len(pila)
def esta_vacia(pila):
return not pila
print esta_vacia(stack)
print stack.pop()
print stack.pop()
print stack.pop()
print esta_vacia(stack)
False 3 2 1 True
#Si hacemos pop() de una lista vacía obtenemos un error
stack.pop()
--------------------------------------------------------------------------- IndexError Traceback (most recent call last) <ipython-input-10-505a7268d9a8> in <module>() 1 #Si hacemos pop() de una lista vacía obtenemos un error ----> 2 stack.pop() IndexError: pop from empty list
#Debemos tener en cuenta
if not esta_vacia(stack):
stack.pop()
El comportamiento de una cola se puede describir con la frase "Lo primero que se encoló es lo primero que se usa". Es decir, su estructura es FIFO (First in, First out)
Un ejemplo básico podría ser la cola en un cajero, donde la primera persona que llegue, es la primera en utilizar el cajero.
True
si la cola está vacíaSuponiendo que implementamos una cola usando una lista. ¿Cómo se podría implementar? ¿Cuál sería el costo?
Problema: En el primer caso encolar y en el segundo caso desencolar del principio implica desplazar todo el contenido de la lista (en un sentido u otro). Esta operación es costosa, imaginense una lista muy grande!
append()
from collections import deque
queue = deque(["Alicia", "Bernardo", "Carlos"])
queue.append("Daniel")
queue
deque(['Alicia', 'Bernardo', 'Carlos', 'Daniel'])
type(queue)
collections.deque
popleft()
queue.popleft()
'Alicia'
Programar la función invertir_pila
que reciba una pila y devuelva otra nueva con sus elementos en orden inverso.
Usar solamente las funciones:
append()
pop()
esta_vacia()
from collections import deque
def invertir_pila(pila):
pila_nueva = []
cola = deque()
while not esta_vacia(pila):
elem = pila.pop()
cola.append(elem)
while not esta_vacia(cola):
elem = cola.popleft()
pila_nueva.append(elem)
return pila_nueva
pila = [1,2,3,4,5,6,7,8,9]
invertir_pila(pila)
[9, 8, 7, 6, 5, 4, 3, 2, 1]
Guarda una notación similar a la matemática para definir conjuntos.
Ejemplo:
def n_pares(n):
lista = []
for x in xrange(1,n+1):
lista.append(x*2)
return lista
n_pares(10)
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
def n_pares(n):
return [2*x for x in xrange(1,n+1)]
n_pares(10)
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
def mayores_a_n(lista, n):
nueva_lista = []
for x in lista:
if x>n:
nueva_lista.append(x)
return nueva_lista
mayores_a_n([3,1,4,6,2,3,2],2)
[3, 4, 6, 3]
def mayores_a_n(lista, n):
return [x for x in lista if x>n]
mayores_a_n([3,1,4,6,2,3,2],2)
[3, 4, 6, 3]
[<expresion> for <item> in <secuencia> if <condicion>]
Implementar las funciones map y filter con listas por comprensión
Ayuda:
def _map(funcion, lista):
return [funcion(x) for x in lista]
def cuadrado(x):
return x**2
lista = [1,2,3,4,5]
_map(cuadrado, lista)
[1, 4, 9, 16, 25]
def _filter(funcion, lista):
return [x for x in lista if funcion(x)]
def mayor_que_5(x):
return x > 5
lista2 = [1,6,3,5,3,4,8,5]
_filter(mayor_que_5, lista2)
[6, 8]
vec = [1,2,3]
[(x,x**2) for x in vec]
[(1, 1), (2, 4), (3, 9)]
for
¶vec1 = [1,2,3]
vec2 = ["a","b","c"]
[(x,y) for x in vec1 for y in vec2]
[(1, 'a'), (1, 'b'), (1, 'c'), (2, 'a'), (2, 'b'), (2, 'c'), (3, 'a'), (3, 'b'), (3, 'c')]
mat = [[1,2,3],
[4,5,6],
[7,8,9]
]
print [[fila[i] for fila in mat] for i in [0, 1, 2]]
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
{x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}
¿Qué genera el siguiente código?
uno = [1,2,3]
dos = ["a","b","c"]
{x:y for x in dos for y in uno}
{'a': 3, 'b': 3, 'c': 3}
Implementar una función que recibe una lista y devuelve la lista invertida, usando listas por comprensión
def invertir(lista):
return [lista[i] for i in range(len(lista) - 1, -1, -1)]
invertir([1,2,3,4])
[4, 3, 2, 1]
def invertir(lista):
return [lista[-(i+1)] for i in xrange(len(lista))]
invertir([1,2,3,4])
[4, 3, 2, 1]
Los problemas se descomponen en un conjunto de funciones que toman entradas, y producen salidas, sin almacenar ningún estado interno
Herramientas funcionales en Python:
A partir de Python 3.x algunas hay que importarlas
doble = lambda x: x*2
doble(2)
4
suma = lambda x,y: x+y
suma(1,2)
3
maximo = lambda x,y: x if x > y else y
maximo(3,7)
7
lista = [1, 2, 3, 4, 5]
map(lambda x: x*2, lista)
[2, 4, 6, 8, 10]
A dos listas
lista_uno = ["Hola", "como", "soy"]
lista_dos = ["Juan", "estas?", "Pedro"]
map(lambda x,y: x + " " + y, lista_uno, lista_dos)
['Hola Juan', 'como estas?', 'soy Pedro']
filter(lambda x: x % 2 == 0, range(11))
[0, 2, 4, 6, 8, 10]
Sin función
lista = [True, 0, False, "cadena", 4, "", [], (5,2), {}, None, 3.14]
filter(None, lista)
[True, 'cadena', 4, (5, 2), 3.14]
# Ejemplo sumatoria
suma = lambda x, y: x + y
print reduce(suma, [1, 2, 3, 4, 5])
# Ejemplo máximo
print reduce(max, [1,4,2,6,9,3,4,5])
15 9
Implementar una función que devuelve la cantidad de elementos en una lista que verifican una condición dada.
def cuantos_cumplen(condicion, lista):
return reduce(lambda x,y:x+y, map(condicion, lista))
def cuantos_cumplen_legible(condicion, lista):
parcial = map(condicion, lista)
suma = lambda x,y: x+y
return reduce(suma, parcial)
def cuantos_cumplen2(condicion, lista):
return len(filter(condicion,lista))
condicion = lambda x: x>5
lista = [1,2,4,5,7,8,9,7]
cuantos_cumplen_legible(condicion, lista)
4
for
__next__()
__next__()
me permite acceder a cada elemento del contenedor, uno a la vez.StopIteration
__iter__()
y __next__()
se crean automáticamentedef primeros_n_cuadrados(n):
num = 0
nums = []
while num < n:
nums.append(num**2)
num += 1
return nums
primeros_n_cuadrados(100)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209, 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, 3969, 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, 9216, 9409, 9604, 9801]
Pero si n es muy grande, estaríamos almacenando una lista muy grande en memoria (cómo pasaba con range
) ...
def primeros_n_cuadrados(n):
num = 0
while num < n:
yield num**2
yield num*2
num += 1
ret1 = primeros_n_cuadrados(10)
print ret1
print list(ret1)
<generator object primeros_n_cuadrados at 0x10437edc0> [0, 0, 1, 2, 4, 4, 9, 6, 16, 8, 25, 10, 36, 12, 49, 14, 64, 16, 81, 18]
def primeros_n_cuadrados(n):
# Generador estilo list comprehension
return (x**2 for x in xrange(n))
ret = primeros_n_cuadrados(10)
print type(ret)
print list(ret)
<type 'generator'> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Implementar un generator que me permita obtener los primeros n valores de la secuencia de fibonacci
fibo(0) = 0
fibo(1) = 1
fibo(2) = 1
fibo(3) = 2
.
.
.
fibo(n) = fibo(n-1) + fibo(n-2)
def fiboGenerator(n):
a, b = 0, 1
contador = 0
while contador < n:
yield a
a, b = b, a + b
contador += 1
return
Dadas dos listas de enteros del mismo largo, implementar una función que devuelva una lista en la que cada elemento es el producto de los elementos de mismo indice de las listas originales. Usar listas por comprensión.
Ayuda: zip()
def producto_de_listas(vecA, vecB):
return [x * y for x,y in zip(vecA, vecB)]
lista1 = [1,2,3]
lista2 = [4,5,6]
producto_de_listas(lista1, lista2)
[4, 10, 18]
def imprime(saludo="Hola", persona="Juan"):
print saludo, persona
imprime()
imprime("Chau")
imprime("Como andas?", "Pedro")
Hola Juan Chau Juan Como andas? Pedro
imprime(persona="Miguel")
imprime(persona="Mati", saludo="Adios")
Hola Miguel Adios Mati
def imprime_de_todo(*elementos):
for elemento in elementos:
print elemento
imprime_de_todo("Hola")
imprime_de_todo("Hola", "Como", "Andas")
Hola Hola Como Andas
def recibe_tres_parametros(pUno, pDos, pTres):
print("a:", pUno, ", b:", pDos, ", c:",pTres)
recibe_tres_parametros(1,2,3)
recibe_tres_parametros(*(1,2,3))
recibe_tres_parametros(*[1,2,3])
recibe_tres_parametros(*[1,2,3,4])
('a:', 1, ', b:', 2, ', c:', 3) ('a:', 1, ', b:', 2, ', c:', 3) ('a:', 1, ', b:', 2, ', c:', 3)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-44-7e4904c806b5> in <module>() 5 recibe_tres_parametros(*(1,2,3)) 6 recibe_tres_parametros(*[1,2,3]) ----> 7 recibe_tres_parametros(*[1,2,3,4]) TypeError: recibe_tres_parametros() takes exactly 3 arguments (4 given)
def imprime_elementos(**elementos):
for clave, valor in elementos.items():
print(clave, ":", valor)
imprime_elementos(uno = 1)
('uno', ':', 1)
imprime_elementos(uno = 1, letra_a = "a")
('letra_a', ':', 'a') ('uno', ':', 1)
imprime_elementos(uno = 1, letra_a = "a", una_lista = [])
('una_lista', ':', []) ('letra_a', ':', 'a') ('uno', ':', 1)
def recibe_tres_parametros(pUno, pDos, pTres):
print("a:", pUno, ", b:", pDos, ", c:",pTres)
dicc = {"pDos": "que", "pUno": "Hola", "pTres": "tal?"}
recibe_tres_parametros(**dicc)
('a:', 'Hola', ', b:', 'que', ', c:', 'tal?')
dicc2 = {"pDos": 22, "pUno": 11, "pTres": 33}
recibe_tres_parametros(**dicc2)
('a:', 11, ', b:', 22, ', c:', 33)
dicc2 = {"pDos": 22, "pUno": 11, "pTre": 33}
recibe_tres_parametros(**dicc2)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-52-ef3358a4dc18> in <module>() 1 dicc2 = {"pDos": 22, "pUno": 11, "pTre": 33} ----> 2 recibe_tres_parametros(**dicc2) TypeError: recibe_tres_parametros() got an unexpected keyword argument 'pTre'
'{0}, {1}, {2}'.format('a', 'b', 'c')
'a, b, c'
'{2}, {1}, {0}'.format('a', 'b', 'c')
'c, b, a'
'{2}, {1}, {0}'.format(*'abc')
'c, b, a'
'{0}{1}{0}'.format('abra', 'cad')
'abracadabra'
'Coordinates: {latitude},{longitude}'.format(latitude='37.24N', longitude='-115.81W')
'Coordinates: 37.24N,-115.81W'
coord = {'latitude': '37.24N', 'longitude': '-115.81W'}
'Coordinates: {latitude},{longitude}'.format(**coord)
'Coordinates: 37.24N,-115.81W'
c = 3 + 5j
'Numero: {0}. Parte real: {0.real}.Parte imaginaria {0.imag}.'.format(c)
'Numero: (3+5j). Parte real: 3.0.Parte imaginaria 5.0.'
coord = (3, 5)
'X: {0[0]}; Y:{0[1]}'.format(coord)
'X: 3; Y:5'
unittest
es una versión en Python de JUnit
. También llamado PyUnit
Soporta:
Test case: unidad de prueba
Test suite: grupo de pruebas que se corren en conjunto
Test fixture: preparación necesaria para correr pruebas
class TestMiModulo(unittest.TestCase):
Convención: la clase comienza con “Test”. Hereda de TestCase, definido en el módulo unittest
python TestModulo.py
python TestModulo.py -v
Método | Chequea que | Nuevo en |
---|---|---|
assertEqual(a,b) |
a==b | |
assertNotEqual(a,b) |
a!=b | |
assertTrue(x) |
bool(x) is True | |
assertFalse(x) |
bool(x) is False | |
assertIs(a,b) |
a is b | 2.7 |
assertIsNot(a,b) |
a is not b | 2.7 |
assertIsNone(x) |
x is None | 2.7 |
assertIsNotNone(x) |
x is not None | 2.7 |
assertIn(a,b) |
a in b | 2.7 |
assertNotIn(a,b) |
a not in b | 2.7 |
assertIsInstance(a,b) |
isinstance(a,b) | 2.7 |
assertIsNotInstance(a,b) |
not isinstance(a,b) | 2.7 |