1 - Instalación y configuración del entorno

Instalación de un intérprete

En Linux tenemos que instalar también python-dev si se van a instalar algunas librerías.

Instalación de un editor

Extensiones de Visual Studio Code

1.1 - Ejercicio de depuración

Introducción a la depuracion de código Python con VS Code

Depurar

Objetivo

En este ejercicio, los estudiantes deberán depurar un programa Python que intenta realizar una búsqueda binaria en una lista ordenada de números. El programa tiene varios errores, y los alumnos deberán utilizar las herramientas de debug de VS Code para identificar y corregir estos problemas.

Instrucciones

  1. Crea un nuevo archivo Python (debug_binsearch.py) en un nuevo proyecto en VS Code.
  2. Pega el siguiente código, que tiene varios errores intencionados:
# debug_binsearch.py
# Este programa tiene errores. Tu tarea es usar el debug de VS Code para encontrarlos y corregirlos.

def binary_search(arr, x):
    low = 0
    high = len(arr)

    while low <= high:
        mid = (low + high) / 2  # Error intencionado
        mid_val = arr[mid]  # Error intencionado

        if mid_val < x:
            low = mid + 1
        elif mid_val > x:
            high = mid - 1
        else:
            return mid  # Encuentra el valor

    return -1  # Valor no encontrado

if __name__ == "__main__":
    arr = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
    x = input("Ingrese un número para buscar en la lista: ")  # Error intencionado

    # Realizar búsqueda binaria
    result = binary_search(arr, x)

    if result != -1:
        print(f"El número {x} está en la posición {result} de la lista.")
    else:
        print(f"El número {x} no se encuentra en la lista.")
  1. Coloca breakpoints en las líneas que consideres relevantes para encontrar los errores.
  2. Inicia el debug (puedes hacerlo presionando F5 o yendo a la barra lateral de “Run and Debug”).
  3. Observa las variables, la salida y el flujo del programa para identificar los errores.
  4. Corrige los errores que encuentres y reinicia el debug para confirmar que el programa funciona correctamente.
Errores a Corregir
  1. mid = (low + high) / 2 calcula mid como un número de punto flotante. Debe ser un entero para indexar la lista. Puede corregirse como mid = (low + high) // 2.
  2. high = len(arr) debería ser high = len(arr) - 1 para evitar el acceso fuera de rango.
  3. El valor ingresado x es una cadena. Debe ser convertido a un entero antes de pasarlo a la función binary_search.

if __name__ == "__main__"

Por supuesto, el bloque if __name__ == "__main__": es un patrón común en programas Python.

Cuando ejecutas un script en Python, el intérprete asigna un valor especial a la variable __name__. Este valor será "__main__" si el script se está ejecutando como programa principal. Pero si el script se importa como un módulo en otro script, el valor de __name__ será el nombre del archivo del script (sin la extensión .py).

En otras palabras, if __name__ == "__main__": permite diferenciar entre los dos escenarios: ¿se está ejecutando este archivo Python como programa principal o se está importando en otro script como un módulo?

¿Para qué se usa?

Este bloque se usa principalmente por dos razones:

  1. Modularidad: Al poner el código bajo este bloque, te aseguras de que ese código solo se ejecute cuando el script sea el programa principal. Esto permite que otros scripts importen funciones y clases de este script sin ejecutar todo el código inmediatamente al importarlo.

  2. Organización del Código: Al colocar el “código de arranque” del script bajo este bloque, se separa claramente la definición de funciones y clases del código que realmente inicia la lógica del programa. Esto hace que el código sea más legible y mantenible.

Un ejemplo

Supongamos que tienes un script llamado mi_script.py con el siguiente contenido:

# Definición de una función
def imprimir_saludo(nombre):
    print(f"Hola, {nombre}.")

# Código de arranque
if __name__ == "__main__":
    imprimir_saludo("Alice")

Si ejecutas mi_script.py directamente (python mi_script.py), verás la salida Hola, Alice. porque el script se está ejecutando como programa principal y, por lo tanto, __name__ es igual a "__main__".

Ahora, si importas mi_script.py en otro script:

import mi_script

mi_script.imprimir_saludo("Bob")

Verás la salida Hola, Bob. pero no verás Hola, Alice. Esto es porque al importar mi_script, la variable __name__ en mi_script.py no es "__main__", por lo que el bloque if __name__ == "__main__": no se ejecuta.

2 - Entrada y Salida

Ejercicio Práctico: Calculadora de Índice de Masa Corporal (IMC)

Objetivo

El objetivo de este ejercicio es crear un programa en Python que calcule el Índice de Masa Corporal (IMC) de una persona. El programa deberá pedir la altura en metros y el peso en kilogramos, calcular el IMC y mostrar un mensaje con el resultado.

Fórmula del IMC

El IMC se calcula con la siguiente fórmula:

$$\text{IMC} = \frac{\text{Peso en kg}}{( \text{Altura en m} )^2}$$

Instrucciones

  1. Crea un nuevo archivo Python y nómbralo calculadora_imc.py.
  2. Utiliza la función input() para obtener el peso y la altura del usuario. Asegúrate de convertir estas entradas a números flotantes para poder hacer cálculos con ellos.
  3. Usa la fórmula del IMC para calcular el índice.
  4. Utiliza la función print() para mostrar el IMC calculado. Asegúrate de que el resultado se muestre con dos decimales.
Código de ejemplo
# Obtener peso del usuario
peso = float(input("Por favor, introduce tu peso en kilogramos: "))

# Obtener altura del usuario
altura = float(input("Por favor, introduce tu altura en metros: "))

# Calcular IMC
imc = peso / (altura ** 2)

# Mostrar el resultado
print(f"Tu Índice de Masa Corporal (IMC) es: {imc:.2f}")

Ampliación

  1. Agrega validaciones para asegurarte de que el usuario no introduzca números negativos o cero.
  2. Extiende el programa para que, además de mostrar el IMC, indique si el usuario está bajo de peso, en su peso ideal o tiene sobrepeso, según la escala de IMC.

3 - Clases

Ejercicios

  • Open In Colab

Ejercicio 1: Clase Persona

Crea una clase llamada Persona que tenga un atributo nombre y un método saludar que imprima “Hola, soy [nombre]”.

Ejercicio 2: Clase Librería

Descripción:

La clase Libreria tendrá un conjunto de libros disponibles y permitirá realizar ciertas operaciones como añadir libros, quitar libros y listar los libros disponibles.

Código:

class Libreria:
    def __init__(self):
        self.libros = []
        
    def agregar_libro(self, titulo):
        self.libros.append(titulo)
        print(f"Se ha agregado el libro '{titulo}'.")
        
    def quitar_libro(self, titulo):
        if titulo in self.libros:
            self.libros.remove(titulo)
            print(f"Se ha quitado el libro '{titulo}'.")
        else:
            print(f"El libro '{titulo}' no está en la librería.")
            
    def listar_libros(self):
        if self.libros:
            print("Libros disponibles en la librería:")
            for libro in self.libros:
                print(f"- {libro}")
        else:
            print("La librería está vacía.")

# Instanciamos la libreria
mi_libreria = Libreria()

# Añadimos algunos libros
mi_libreria.agregar_libro("1984")
mi_libreria.agregar_libro("Cien años de soledad")

# Listamos los libros
mi_libreria.listar_libros()

# Quitamos un libro
mi_libreria.quitar_libro("1984")

# Listamos de nuevo los libros
mi_libreria.listar_libros()

Tareas:

Tarea 1: Método para buscar un libro

Añade un método llamado buscar_libro que tome un título como parámetro y diga si el libro está o no en la librería.

Tarea 2: Contador de libros

Añade un método llamado contar_libros que devuelva el número total de libros en la librería.

4 - Decoradores

¿Qué es un Decorador en Python?

Un decorador es una función que toma una función como entrada y devuelve una nueva función. Se usan para modificar el comportamiento de las funciones o clases de una manera limpia, reutilizable y legible.

Sintaxis

La sintaxis básica para usar un decorador es preceder la definición de una función con el símbolo @ seguido del nombre del decorador.

@decorador
def mi_funcion():
    pass

¿Cómo Funcionan?

Veamos un ejemplo sencillo de cómo funciona un decorador. Supongamos que deseamos medir el tiempo que toma la ejecución de una función.

import time

def timer_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"{func.__name__} se ejecutó en {end_time - start_time} segundos")
        return result
    return wrapper

@timer_decorator
def mi_funcion(n):
    suma = 0
    for i in range(n):
        suma += i
    return suma

Cuando llamamos a mi_funcion, en realidad estamos llamando a wrapper, que a su vez llama a mi_funcion, permitiéndonos hacer cosas antes y después de que se ejecute mi_funcion sin modificar su código.

Utilidad

  1. Separación de Responsabilidades: Los decoradores ayudan a seguir el principio de separación de responsabilidades al extraer la lógica que no está directamente relacionada con la tarea de una función.

  2. Reusabilidad: Una vez que tienes un decorador, puedes usarlo en múltiples funciones.

  3. Modificación Dinámica: Permiten modificar el comportamiento de una función o clase sin tener que modificar su código fuente.

  4. Legibilidad: Mejoran la legibilidad al etiquetar las funciones con su comportamiento adicional.

5 - Errores y Excepciones

The try-except block

When you think an error may occur, you can write a try-except block to handle the exception that might be raised. The try block tells Python to try running some code, and the except block tells Python what to do if the code results in a particular kind of error.

Ejemplo: Handling the ZeroDivisionError exception

try:
    print(5/0)
except ZeroDivisionError:
    print("You can't divide by zero!")

Ejemplo: Handling the FileNotFoundError exception

from pathlib import Path
path = Path("siddhartha.txt")
try:
    contents = path.read_text()
except FileNotFoundError:
    msg = f"Can’t find file: {path.name}."
    print(msg)

else block

prompt = "How many tickets do you need? "
num_tickets = input(prompt)
try:
    num_tickets = int(num_tickets)
except ValueError:
    print("Please try again.")
else:
    print("Your tickets are printing.")

Knowing which exception to handle

It can be hard to know what kind of exception to handle when writing code. Try writing your code without a try block, and make it generate an error. The traceback will tell you what kind of exception your program needs to handle.

6 - Información en archivos. Texto, CSV, JSON, HTML, XML

En este bloque vamos a ver cómo se trabaja con distintos formatos de archivos con Python.

6.1 - Archivos de texto

6.2 - Archivos CSV

Documentación

Notebook Base

  • Open In Colab
  • 🛠️ Open In Colab

El formato de archivos CSV

CSV significa “Comma-Separated Values” (Valores Separados por Comas), y es un formato de archivo que almacena datos tabulares en forma de texto. Un archivo CSV esencialmente consta de una o más filas, y cada campo en la fila está separado por una coma. Este es un ejemplo muy simple:

Nombre,Edad,Correo
Alice,30,alice@email.com
Bob,45,bob@email.com
Charlie,25,charlie@email.com

La primera fila a menudo contiene encabezados que describen qué datos se encuentran en cada columna. Sin embargo, esto no es estrictamente necesario. Los archivos CSV son muy flexibles y pueden ser abiertos o editados con un simple editor de texto o con software más avanzado como una hoja de cálculo.

Formato muy usado en la ciencia de datos y en IoT debido a su simplicidad, eficiencia y versatilidad. Su capacidad para almacenar datos de manera estructurada pero simple lo convierte en una opción popular para una variedad de aplicaciones.

6.3 - Archivos JSON

¿Qué es JSON?

JSON (JavaScript Object Notation) es un formato de intercambio de datos ligero y de fácil lectura para humanos. Está basado en un subconjunto del lenguaje de programación JavaScript y es muy similar a los diccionarios en Python. Aunque fue originado en JavaScript, se ha convertido en un formato estándar para el intercambio de datos entre diferentes lenguajes y aplicaciones.

¿Por qué es importante JSON en Python?

  1. Interoperabilidad: JSON es un formato ampliamente aceptado para el intercambio de datos en aplicaciones web.
  2. Facilidad de Uso: La sintaxis de JSON es sencilla y fácil de leer/escribir.
  3. Estructura de Datos Anidados: Permite anidar arrays y objetos, lo cual es especialmente útil para almacenar datos más complejos.

Bibliotecas para manipular JSON en Python

La biblioteca estándar de Python incluye el módulo json, que permite codificar y decodificar datos en formato JSON.

  • json.dump() / json.dumps(): Para escribir datos en JSON.
  • json.load() / json.loads(): Para leer datos en JSON.

Ejercicios Propuestos

Ejercicio 1: Leer y modificar datos JSON

  1. Leer un archivo JSON que contiene una lista de productos. Cada producto debe tener un nombre, precio y cantidad_en_stock.
  2. Incrementar el precio de cada producto en un 10%.
  3. Guardar los datos modificados en un nuevo archivo JSON.

Ejercicio 2: Análisis de Datos JSON

  1. Leer un archivo JSON que contiene datos sobre diversas ciudades, incluyendo el nombre, población, y altitud.
  2. Encontrar y mostrar la ciudad con la mayor y la menor población.
  3. Guardar esta información en un nuevo archivo JSON titulado analisis_ciudades.json.

Estos elementos deberían proporcionar una base sólida para enseñar la manipulación de archivos JSON en Python. Puedes adaptar los ejemplos y ejercicios según las necesidades de tus alumnos.

7 - Proyecto 2

Visualizador de canales de TDT a partir de un archivo JSON

En este repositorio https://github.com/LaQuay/TDTChannels tienes información sobre canales de TDT de España en formato JSON.

Usa el archivo https://www.tdtchannels.com/lists/tv.json para crear un visualizador de los canales de TDT.

Si lo quieres ver en el navegador, necesitarás una extensión para ver archivos m3u.

Open In Colab

Variante: uso de streamlit

no podrás ejecutarlo en colab, sino en tu equipo. Para ejecutarlo en colab, tendrías que usar alguna herramienta como ngrok.

Aquí tienes un ejemplo de aplicación que usa streamlit https://github.com/lmorillas/streamlit-tdt/

Para ejecutar en tu equipo, tienes que

  • clonar el repositorio
$ git clone c

* crear entorno virtual
```bash
$ cd streamlit-tdt
$ python3 -m venv env
$ source env/bin/activate
  • instalar dependencias
$ pip install -r requirements.txt
  • ejecutar la aplicación
$ streamlit run tdt.py

Modifica el programa

  • Que muestre los canales
  • Que permita otras búsquedas directas.

Ejercicios propuestos

  • Añade una caja de búsqueda para filtrar los canales por nombre.
text_search = st.text_input("Buscar canal de TV", value="")