Apuntes sobre Python: Las Colecciones

Las colecciones pertenecen a los tipos básicos de datos en Python. Una colección es un objeto que almacena un grupo de objetos que no deben porque ser todos del mismo tipo.

Existen seis tipos de colecciones diferentes:

  1. Listas
  2. Tuplas
  3. Diccionarios
  4. Conjuntos
  5. Pilas
  6. Colas

Las listas

  • Es un tipo de colección ordenada.
  • Puede contener cualquier tipo de dato.
  • Sus datos son mutables.
  • Su constructor son los corchetes: [ ]
lista = ['valor', 1, True, ['lista', 2, 'esta vez anidada']]

Para acceder a un valor de la lista se puede

  • Indicar la posición del elemento entre los corchetes.
  • Hacer uso del slicing. (Ver slice)
lista[0]  # 'valor'
lista[0:2]  # ['valor', 1]
lista[:-2] # ['valor', 1]
lista[-1]  # ['lista', 2, 'esta vez anidada']
lista[-1][2]  # 'esta vez anidada'

Los índices pueden ser negativos, lo que permite comenzar la búsqueda por el final de la lista.

Funciones:

  1. append(value)
  2. insert(value)
  3. remove(i)
  4. clear()
  5. index(value)
  6. count()
  7. sort(key=None, reverse=False)
  8. reverse()

Las tuplas

  • Es un tipo de colección ordenada.
  • Puede contener cualquier tipo de dato.
  • Sus datos son inmutables. (Una vez establecidos, no pueden ser modificados)
  • Su constructor es la coma, aunque por convención se hace uso de los paréntesis: ( )
t = 1,  # type(t) -> tuple
i = 1  # type(i) -> int

t = (1,)  # type(t) -> tuple
i = (1)  # type(i) -> int

t = (1, 2,) # type(t) -> tuple
i = (1, 2) # type(i) -> tuple

Como se puede apreciar, cuando se declara una tupla de un único elemento se hace necesario el uso de una coma.

Para acceder a un valor de la lista se puede hacer uso de los corchetes (Sigue las mismas reglas que las listas)

  • Indicar la posición del elemento entre los corchetes.
  • Hacer uso del slicing. (Ver slice)
t[0]t[-1]

Funciones

  1. index(value)
  2. count()

Los diccionarios

Son de las colecciones más utilizadas en Python. Se basan enuna estructura mapeada donde cada elemento de la colección es almacenado con una clave única.

Como clave de un diccionario podríamos utilizar cualquier valor inmutable, como números, cadenas, booleanos, tuplas, etc. pero no listas ni otros diccionarios.

  • Es un tipo de colección desordenada.
  • Puede contener cualquier tipo de dato.
  • Sus datos son mutables.
  • Su constructor son las llaves: { }
traducciones = {
    'car' :'coche',
    'table': 'mesa'
}
traducciones['car']  # coche

Para acceder a un valor de la lista se puede hacer uso de los corchetes

  • Indicar la posición del elemento entre los corchetes.
  • No se puede hacer uso del slicing debido a que un diccionario no es una secuencia, si no un mapping (mapeados, asociaciones).

Funciones

  1. len(dict)
  2. del(dict[key])
  3. iter(dict)
  4. clear(dict)
  5. copy()
  6. get(key)
  7. items()
  8. keys()
  9. pop(key)
  10. popitem()
  11. values()

Los conjuntos

  • Es un tipo de colección desordenadas de elementos únicos.
  • Puede contener cualquier tipo de dato.
  • Su constructor son las llaves: { }
conjunto = set()  # type(conjunto) -> set
conjunto = set([1, True, 'A'])  # type(conjunto) -> set
conjunto = { }  # type(conjunto) -> set

Gracias a que los conjuntos reciben en el constructor set como parámetro una lista, mediante el casteo de objetos podemos eliminar de una lista todos los duplicados. Veamos un ejemplo:

l = [1, 2, 4, 5, 3, 4, 5]
l = list(set(l))
print(l)  # [1, 2, 3, 4, 5]

El uso más frecuente que se le da a los conjuntos son las pruebas de pertenencia al grupo, a parte de la eliminación de duplicados como hemos visto antes. Para realizar una prueba de pertenencia haremos uso de la palabra reservada in.

conjunto = set([1, True, 'A'])
'A' in conjunto # True
'2' in conjunto # False

Funciones

  1. len(set)
  2. union(set)
  3. difference(set)
  4. copy()
  5. add(elem)
  6. remove(elem)
  7. discard(elem)
  8. pop()
  9. clear()

Las pilas

Python no implementa directamente pilas, pero se pueden simular con listas.

Una pila será siempre una lista, por lo que se le aplicarán todas sus características. Pero tiene algunas particularidades a la hora de la inserción y la consulta de valores.

A nivel lógico, una pila solo debe permitir realizar dos acciones sobre una colección de datos.

  1. Añadir (push) un elemento a la pila.
  2. Sacar (pop) el último elemento añadido a la pila.

En una pila, el último elemento en entrar, es el primero en salir.

En inglés, se conoce a las pilas como estructuras LIFO (Last IN, First OUT).

pila = [1, 2, 3]
pila.pop()  # 3

La cola

Python no implementa directamente colas, pero se pueden simular con listas.

Una cola será siempre una lista, por lo que se le aplicarán todas sus características. Pero tiene algunas particularidades a la hora de la inserción y la consulta de valores.

A nivel lógico, una cola solo debe permitir realizar dos acciones sobre una colección de datos.

  1. Encolar (append) un nuevo valor al final de la cola.
  2. Desencolar (popleft) el primer elemento añadido a la cola. (REQUIERE IMPORTAR deque)
from collections import deque

En inglés, se conoce a las colas como estructuras FIFO (First IN, First OUT).

cola = deque() cola.append('coche', 'silla')
cola.popleft()  # coche

Apuntes sobre Python: Control de flujo

Condicionales If, elif, else

Permite añadir expresiones lógicas y/o relacionales para modificar el flujo del programa. Permitiendo modificar el comportamiento del mismo.

if(1 == 1):
    print('Estamos dentro!')
else:
    print('Nunca me voy a ejecutar, pues 1 es siempre 1')
cosa = 1 # Imaginemos que este valor nos lleva por tecladoif(cosa):
    print('Cosa es True, ya que un valor diferente de cero siempre será verdadero')
else:
    print('Cosa contiene %s como valor' % valor)
# Asignación múltiple. Simplemente lo hago así para que veáis otra manera de asignar variablesnombre, edad, telefono, trabaja = 'Marta', 27, 666666666, Falseif(edad >= 18 and not trabaja):    print('Debemos contratar a %s, ya que está parada!' % nombre)elif(not trabaja)
    print('%s es menor de edad y no trabajar' % nombre)
else:
    print('%s es mayor de edad y trabaja, enorabuena!' % nombre)

Bucles while y for

Con los bucles podemos ejecutar conjuntos de sentencias de manera reiterativa hasta que cierta condición sea incumplida.

While

Permite evaluar sentencias que devolverían un valor booleano. En el momento que la sentencia retorne False, el bucle finalizará.

# Se repetirá constantemente hasta respuesta tenga un valor.
respuesta = None
while(not respuesta):
 respuesta = input('Falta mucho?')

For

Con el bucle de tipo for se puede iterar de una manera más limpia que con while, debido a que está preparado para trabajar con listas.

valores = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9,]for valor in valores:    print(valor)

El ejemplo iterará por cada elemento de ‘valores’ y almacenará el valor de cada iteración sobre la variable ‘valor’ hasta finalizar la lista.

Cuando for se ejecuta, crea una copia de la lista para la iteración, por lo que si intentamos realizar alguna modificación sobre la lista iterada no estaremos modificando realmente la lista. Si deseamos realizar modificaciones sobre la propia lista, deberemos hacerlo asignando a la lista un valor mediante el uso de un índice. Por ejemplo:

valores = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9,]
index = 0
for valor in valores:
    valor[index] += 1
    index += 1

Así, habremos modificado todos los valores de ‘valores’ gracias al apuntar a los valores de la lista.

También podríamos iterar sobre cadenas de texto, solo que en este caso en vez de recorrer las posiciones de una lista, recorrerá las posiciones de la cadena.

salida = ''
cadena = 'esto es una cadena'
for c in cadena:
 salida += c
print('la salida es "%s", y la cadena era "%s", ¡Que ejemplo más tonto! :D' % (salida, cadena))

La función enumerate, la vorágine entre los bucles…

enumerate es una función propia del lenguaje de Python que al pasarle una lista nos devuelve una lista de tuplas con el formato (índice, valor). Lo explicamos con un ejemplo:

valores = [1,2,3,4,5,6,7,8,9,]
for i, v in enumerate(valores):
 v[i] = v + 1
 
print(valores)  # 'valores' habrá incrementado todos sus valores en uno.

La función range, la manera simple de iterar ‘n’ veces…

La función range espera recibir como parámetro un integer y devolverá una lista de tantos elementos como el parámetro de entrada. De esta forma podremos realizar iteraciones limitadas por un valor numérico.

# Mostrará los valores del 0 al 9, ya que ejecutará el bucle 10 veces.
for i in range(10):    print(1)

 

Y para acabar…

Lo que voy a comentar se aplica tanto para while como para for.

Es posible añadir a los bucles la instrucción final else.

else se ejecutará solo si el bucle ha finalizado satisfactoriamente o si no ha llegado a entrar nunca. En otras palabras, nunca será ejecutado si ha entrado en el bucle y se ha producido un break.

while True:
    break
else: 
    print('no me ejecuto porque he sido brakeada')
print('fin')
# En este ejemplo, solo se ejecutaría el print 'fin'

while False:
    print('Esto es un ejemplo malo')
else:
    print('me lees')
print('fin')
# En este otro ejemplo, no entraría en el bucle, se ejecutaría el bloque else (mostrando 'me lees') y finalizaría mostrando el texto 'fin'

Apuntes sobre Python: Operaciones y expresiones

Tipo Lógico

El tipo lógico solo puede representar dos valores, Verdadero y Falso. Representado por los valores True y False respectivamente.

verdadero = True
falso = False

Operadores relacionales

Los operadores relacionales son operadores que nos permiten realizar comparaciones de valores. Si la comparación es verdadera diremos que es True, mientras que si la evaluación es falsa diremos que es False.

Ejemplos:

1 == 0  # Igual que
1 != 0  # Distinto de
1 > 0  # Mayor que
1 < 0  # Menor que
1 >= 0  # Mayor o igual que
1 <= 0  # Menor o igual que
'Patata' == 'Patata'  # True
'Patata' == 'patatA'  # False
'Patata'[2] == 't'  # True

Operadores Lógicos

El operador lógico negado, not

Sencillamente niega la expresión a la que precede.

not True  # False
not 1 == 1  # False
not True == False  # True

El operador lógico de conyunción, and

Al realizar una unión de variables booleanas mediante la conyunción, se realiza la evaluación conjunta de la relación entre las distintas variables implicadas empleando las siguientes reglas mostradas en la tabla.

var.1 var.2 Resultado
False False False
False True False
True False False
True True True

Sólo si todas las variables implicadas son verdaderas, el resultado será verdadero

Operador lógico de disyunción, or

Al realizar una unión de variables booleanas mediante la disyunción, se realiza la evaluación conjunta de la relación entre las distintas variables implicadas empleando las siguientes reglas mostradas en la tabla.

var.1 var.2 Resultado
False False False
False True True
True False True
True True True

Sólo si alguna de las variables implicadas es verdadera, el resultado será verdadero

Las expresiones anidadas

Las expresiones anidadas son aquellas que son usadas entre paréntesis. Una expresión entre paréntesis modificará el orden en el cual va a ser ejecutada referente a las normas básicas de precedencia.

Las reglas de precedencia

  1. Expresiones entre paréntesis
  2. Expresiones aritméticas, las cuales se rigen por las siguientes reglas…
    1. Exponentes y raíces
    2. Multiplicaciones y divisiones
    3. Sumas y restas
  3. Expresiones relacionales (>, >=, ==, !=, <, <=)
  4. Expresiones lógicas (True y False)

Todas estas reglas se aplican siempre de izquierda a derecha.

Importante

En Python podemos expresar los valores booleanos también con números, siendo 0 False y el resto de números True (Ya sean enteros o reales, positivos o negativos)

Comenzando con Python: Preparación entorno de desarrollo

Preparación del entorno de trabajo

Para poder comenzar a desarrollar código deberemos tener instalado Jupyter y virtualenv.

¿Qué es Jupyter? Jupyter es un block de notas web de código abierto que te permitirá crear y compartir documentos con bloques de código los cuales podrán ser ejecutados sobre el propio block de notas.

¿Y virtualenv? Virtualenv es una herramienta que permite la creación de entornos de trabajo aislados dedicados a Python.
Un problema bastante grande que se presenta cuando se inicia en el mundo de la programación en Python, es que los programas que utilizamos requieren de una serie de librerías o utilidades que son instaladas por defecto en una carpeta global (a modo de «gran saco»). Esto en si mismo no es un problema si se sabe lo que se instala y las librerías que tienes instaladas. Pero no siempre una es conocedora de lo que tiene instalado y muchas veces dos programas Python distintos requieren de librerías que entre ellas son incompatibles, lo que acaba generando inconsistencias entre las aplicaciones. Virtualenv previene esos problemas.
Con virtualenv podrás realizar la instalación de todas las librerías de un proyecto Python en un directorio especificado por ti, lo que previene que aparezcan incompatibilidades entre las librerías de los distintos proyectos.

Instalando Jupyter y virtualenv

Ambos programas pueden ser instalados haciendo uso de una pequeña herramienta escrita en python que viene por defecto en nuestros equipos GNU/Linux, la herramienta en cuestión se llama pip y puede ser utilizada directamente desde nuestro terminal.
Sabiendo esto, comencemos con la ejecución de comandos.

pip3 install --upgrade \
 jupyter \
 virtualenv

Al ejecutar estos comandos lo que hemos hecho es instalar los programas jupyter y virtualenv a la vez que los actualizamos a la última versión existente.

¿Fácil, no? :)

Ahora aprenderemos a como iniciar Jupyter

Como hemos dicho, virtualenv permite definir un directorio donde se realizará la instalación de todas las dependencias. Para ello es necesario lanzar una serie de comandos para la creación y la activación del directorio.

Como lo que deseamos es que Jupyter haga uso de dicho directorio, el orden de ejecución será:

  1. Preparar con virtualenv el directorio para las librerías
  2. Ejecutar jupyter «enlazado» a dicho directorio

Bien pues, comencemos.
Lo primero será navegar con el terminal al directorio en el cual queremos crear nuestro nuevo block de notas:

mkdir -p ~/jupyter.d/example.d
cd ~/ jupyter.d/example.d

Este comando habrá creado la carpeta jupyter.d en nuestra carpeta personal y example.d como subcarpeta de jupyter.d

He creado las carpetas con la extensión .d para que se vea claramente que se trata de un «directorio», pero debéis saber que no es algo obligatorio

Ahora, estando dentro de example.d vamos a crear el directorio para instalar todas las librerías que irá necesitando jupyter.

virtualenv .ENV
source .ENV/bin/activate

Una vez ejecutado el comando source, observarás que la línea de comando ha obtenido el prefijo (.ENV), esto quiere decir que ahora se cogerá por defecto como «librería común» la carpeta .ENV en vez de la carpeta global del sistema operativo. Ea, conseguido, ahora a ejecutar el block de notas.

jupyter notebook

Tras ejecutar esta acción, observaremos que se nos abre nuestro navegador web con la dirección http://localhost:8888. ¡Listo, ya tenemos nuestro block de notas web en marcha! Ahora conforme vayamos creando cosas (amo la palabra «cosa» xD) se irán almacenando en ~/jupyter.d/example.d.

Tips básicos

Debido a que la interfaz que presenta Jupyter es batante intuitiva, intentaré ser breve.

Crearemos un nuevo fichero python a modo de prueba, para ver dos cosas básicas. Para ello nos dirigiremos al botón New y seleccionamos la opción Python3, el botón lo tendrás situado en la esquina superior derecha de la tabla que presenta nuestros blocks de notas (la cual, estará vacía y mostrará un mensaje parecido a: The booknote list is empty.)

Esta acción habrá abierto una nueva pestaña en tu navegador con la dirección http://localhost:8888/notebooks/Untitled.ipynb a la vez que habrá creado el archivo Untitled.ipynb en la carpeta ~/jupyter.d/example.d.
No te preocupes por el nombre, lo puedes cambiar, para ello solo debes pinchar en el nombre del block Untitled situado en la vista (justo al lado del logo de Jupyter) y editarlo. Esta acción cambiará también el nombre del block de tu carpeta ~/jupyter.d/example.d.

Podrás observar una caja de texto con el prefijo In [ ]:. Dicho prefijo indica que se trata de un bloque destinado a código Python, vamos a insertar algo de código, prueba a escribir y a continuación, para ejecutar el bloque, presiona shift + enter.

print('Hola mundo!')

Podrás observar dos cosas, por un lado la salida que produce este código y por otro lado que se ha generado un nuevo bloque vacío.

Ahora vamos a cambiar el lenguaje del bloque nuevo generado de Python a lenguaje de marcado, para ello deberás buscar por las opciones de la barra de herramientas un desplegable que muestra el teto Code y cambiarlo por Markdown. Observarás que ha desaparecido el prefijo In [ ]: del bloque (Luego explicaré que es dicho prefijo).

Prueba a escribir en el bloque de markdown y presiona shift + enter para finalizar y ejecutar el bloque:

# Pasos básicos en el inicio a la programación

* Aprender a amar «Hola mundo» por encima de todas las cosas.
* Escribir alguna operación matemática

¿Mola eh? Markdown es un lenguaje que permite generar documentos con títulos, listas, comentarios, tablas y unas cuantas opciones más con una sintaxis muy sencilla que para documentar nuestro código nos va a venir de lujo. Puedes aprender algo de sintaxis de markdown a través de una búsqueda en duckduckgo.com.

Ahora es el momento de explicar In [ ]:. Este prefijo es exclusivo de los bloques de tipo Code y representan el número de ejecuciones que se han realizado del propio bloque. Si seleccionamos nuestro bloque python (El que contenía el «Hola mundo!») y presionamos ctrl + enter observaremos que dicho contador va incrementando por cada pulsación.

La combinación de teclas ctrl + enter ejecuta el bloque de código actual, mientra que la combinación shift` + enter ejecuta el bloque actual y pasa al siguiente bloque (en caso de no existir un bloque a continuación, crea uno nuevo).

Y para acabar…

Cuando nos cansemos de trabajar en jupyter y deseemos cerrarlo, deberemos ir al terminal donde lo ejecutamos y presionar ctrl + C para matar el servidor que habíamos levantado y cerrar correctamente virtualenv con el comando deactivate (Dicho comando eliminará el prefijo (.ENV)).