Creado por Vicente Simón Rando
para el grupo de Mensa Aragón y
Navarra de Mensa España.
Este manual de Python fue generado
con la asistencia de un modelo de
lenguaje grande, entrenado por
Google, Gemini 2.5 Flash.
Julio de 2025, v.1.0
Manual completo de Python para Principiantes
Presentación
Soy Vicente Simón Rando (https://es.linkedin.com/in/vicentesimon), coordinador adjunto del
grupo local de Aragón y Navarra; perteneciene a Mensa España.
Este tutorial de Python lo he realizado, portada incluida, con la inestimable e infable ayuda de
Gemini 2.5 Flash, una herramienta de Inteligencia Artificial, un LLM (Modelo de Gran Lenguaje)
creado por Google.
El propósito inicial de este manual es compartirlo con mis compañeros de la asociación, como
material de apoyo para los talleres y actividades que realizamos en su seno. De este modo,
contribuye a uno de los fines fundamentales de nuestra organización: la promoción del
conocimiento y el intercambio intelectual, tal como se recoge en los objetivos de Mensa
España (https://www.mensa.es).
🛡 Aviso de Licencia
Este manual está protegido por derechos de autor y se distribuye bajo los términos de la licencia
Creative Commons Atribución-NoComercial-SinDerivadas 4.0 Internacional (CC BY-NC-ND 4.0).
Esto significa que:
- Puedes copiarlo, descargarlo y compartirlo libremente en cualquier medio o formato.
- Debes dar crédito adecuado al autor, incluyendo su nombre y la fuente original.
- No puedes utilizar este contenido con fines comerciales ni obtener ningún beneficio económico directo o indirecto a partir de él.
- No puedes modificar, adaptar o transformar este material. Solo se permite su distribución en forma íntegra y sin alteraciones.
Para más detalles sobre esta licencia, visita:
https://creativecommons.org/licenses/by-nc-nd/4.0/deed.es
© Vicente Simón Rando, julio de 2025
Versiones:
Julio de 2025, v.1.0
Vicente Simón Rando
(CC BY-NC-ND 4.0)
2 de 115
Manual completo de Python para Principiantes
Tabla de contenidos
Contenido
Presentación.................................................................................................................................. 2
Tabla de contenidos ...................................................................................................................... 3
1. Introducción al Mundo de Python .......................................................................................... 11
1.1. ¿Qué es Python y Por Qué Aprenderlo? .......................................................................... 11
1.2. Breve Historia y Filosofía de Python ................................................................................ 12
1.3. Áreas de Aplicación: de la Web a la IA ............................................................................. 12
1.4. Instalación de Python (Última Versión)............................................................................ 13
1.5. Configuración del Entorno de Desarrollo: VS Code.......................................................... 14
1.5.1. Instalación y Extensiones Esenciales ......................................................................... 14
1.5.2. Primer "Hola Mundo" en VS Code ............................................................................ 14
1.6. Introducción a Google Colab ............................................................................................ 15
1.6.1. ¿Qué es y Cómo Funciona? ....................................................................................... 15
1.6.2. Creando Nuestro Primer Notebook .......................................................................... 16
2. Fundamentos de Programación con Python ........................................................................... 17
2.1. Conceptos Básicos: Programas, Instrucciones, Comentarios........................................... 17
2.2. Variables y Tipos de Datos Primitivos .............................................................................. 18
Vicente Simón Rando
(CC BY-NC-ND 4.0)
3 de 115
Manual completo de Python para Principiantes
2.2.1. Números (Enteros, Flotantes) ................................................................................... 18
2.2.2. Cadenas de Texto (Strings) ........................................................................................ 19
2.2.3. Booleanos (True/False) ............................................................................................. 20
2.3. Operadores....................................................................................................................... 20
2.3.1. Aritméticos ................................................................................................................ 20
2.3.2. Comparación ............................................................................................................. 21
2.3.3. Lógicos ....................................................................................................................... 21
2.3.4. Asignación ................................................................................................................. 21
2.4. Entrada y Salida de Datos................................................................................................. 22
2.4.1. input(): Recoger Datos del Usuario ..................................................................... 22
2.4.2. print(): Mostrar Información en Pantalla ........................................................... 23
2.4.3. F-Strings: Formateo de Cadenas ............................................................................... 23
3. Estructuras de Control de Flujo ............................................................................................... 24
3.1. Estructuras Condicionales (if, elif, else) ................................................................. 24
3.2. Estructuras Repetitivas (Bucles) ....................................................................................... 25
3.2.1. for: Iteración sobre Secuencias............................................................................... 25
3.2.2. while: Bucle Condicional ........................................................................................ 26
3.2.3. break y continue: Control de Bucles .................................................................. 27
4. Colecciones de Datos .............................................................................................................. 29
4.1. Listas ................................................................................................................................. 29
4.1.1. Creación, Acceso y Modificación ............................................................................... 29
4.1.2. Métodos Comunes (Añadir, Eliminar, Ordenar)........................................................ 30
4.1.3. List Comprehensions (Introducción) ......................................................................... 31
4.2. Tuplas ............................................................................................................................... 33
4.2.1. Creación, Inmutabilidad y Acceso ............................................................................. 33
4.3. Diccionarios ...................................................................................................................... 34
4.3.1. Creación, Acceso por Clave y Modificación............................................................... 34
4.3.2. Métodos Comunes .................................................................................................... 35
Vicente Simón Rando
(CC BY-NC-ND 4.0)
4 de 115
Manual completo de Python para Principiantes
Ejercicio 4.3.1: Agenda Telefónica Sencilla ......................................................................... 36
4.4. Conjuntos (Sets) ............................................................................................................... 36
4.4.1. Creación y Operaciones Básicas ................................................................................ 37
5. Funciones: Modularizando Nuestro Código ............................................................................ 39
5.1. Definición y Llamada de Funciones .................................................................................. 39
5.2. Parámetros y Argumentos ........................................................................................... 40
5.3. Valores de Retorno (return) ......................................................................................... 41
5.4. Ámbito de las Variables (Global y Local) .......................................................................... 42
5.5. Funciones Lambda (Introducción) .................................................................................... 44
6. Manejo de Errores y Excepciones ........................................................................................... 46
6.1. ¿Qué son los Errores y las Excepciones? .......................................................................... 46
6.2. Bloques try, except, else, finally ...................................................................... 47
6.3. Tipos Comunes de Excepciones ....................................................................................... 48
7. Gestión de Módulos y Paquetes ............................................................................................. 51
7.1. Módulos: Organización del Código en Archivos............................................................... 51
7.2. Importar Módulos: import ............................................................................................ 51
7.3. Paquetes: Colecciones de Módulos ................................................................................. 53
7.4. El Administrador de Paquetes pip .................................................................................. 54
7.5. Entornos Virtuales (Introducción Breve) .......................................................................... 55
8. Trabajando con Datos Externos .............................................................................................. 56
8.1. Manejo de Ficheros (Lectura y Escritura) ......................................................................... 56
8.1.1. Abrir, Cerrar y Modos de Apertura ........................................................................... 56
8.1.2. Lectura Línea a Línea y Completa .............................................................................. 57
8.1.3. Escritura de Datos ..................................................................................................... 58
8.2. Persistencia de Datos con JSON ....................................................................................... 59
8.2.1. json Módulo: Cargar y Guardar Datos Estructurados ............................................ 59
8.3. Fechas y Horas (datetime módulo) .............................................................................. 61
8.3.1. Creación, Formato y Operaciones Básicas ................................................................ 61
Vicente Simón Rando
(CC BY-NC-ND 4.0)
5 de 115
Manual completo de Python para Principiantes
9. Librerías Útiles y Aplicaciones Prácticas.................................................................................. 64
9.1. requests: Haciendo Peticiones HTTP (APIs Web) ........................................................ 64
9.1.1. Realizando Peticiones GET ........................................................................................ 64
9.1.2. Parámetros de Consulta y Cabeceras ........................................................................ 65
9.2. re: Expresiones Regulares (Búsqueda de Patrones) ....................................................... 66
9.2.1. Funciones Comunes del Módulo re ......................................................................... 67
9.3. pandas: Análisis de Datos (Introducción Muy Básica) ................................................... 68
9.3.1. Creación de DataFrames y Operaciones Básicas ....................................................... 68
10. ¡Creando y Ejecutando Tu Primer Proyecto Completo! ........................................................ 70
10.1. Planificación del Proyecto: "Gestor de Contactos Avanzado" ....................................... 70
10.2. Estructura del Proyecto .................................................................................................. 71
10.3. Implementación Paso a Paso ......................................................................................... 71
10.4. Cómo Ejecutar el Proyecto ............................................................................................. 73
10.5. Repaso y Consejos para Proyectos ................................................................................. 73
A. Conceptos Adicionales Clave .................................................................................................. 75
A.1. Programación Orientada a Objetos (POO) ....................................................................... 75
A.1.1. Clases y Objetos ........................................................................................................ 75
A.1.2. Atributos y Métodos ................................................................................................. 75
A.1.3. self ......................................................................................................................... 76
A.1.4. Constructores (__init__) ..................................................................................... 76
A.1.5. Herencia .................................................................................................................... 77
A.1.6. Polimorfismo ............................................................................................................. 77
A.1.7. Encapsulamiento ....................................................................................................... 78
A.2. Comprensión de Listas, Diccionarios y Conjuntos (Comprehensions) ............................. 79
A.2.1. Comprensión de Listas (List Comprehensions) ......................................................... 79
A.2.2. Comprensión de Diccionarios (Dict Comprehensions) ............................................. 80
A.2.3. Comprensión de Conjuntos (Set Comprehensions) .................................................. 80
A.3. Decoradores (@) ............................................................................................................... 81
Vicente Simón Rando
(CC BY-NC-ND 4.0)
6 de 115
Manual completo de Python para Principiantes
A.4. Generadores e Iteradores ................................................................................................ 82
A.4.1. Iteradores .................................................................................................................. 82
A.4.2. Generadores ............................................................................................................. 83
A.5. Manejo Básico de Ficheros CSV (csv módulo) ............................................................... 84
A.5.1. Lectura de Archivos CSV............................................................................................ 84
A.5.2. Escritura de Archivos CSV ......................................................................................... 84
B. Propuestas de Ejercicios Adicionales (Con su Solución Breve) ............................................... 86
B.1. Ejercicios de Consolidación (Conceptos ya vistos) ........................................................... 86
B.2. Ejercicios Introductorios a POO (Conceptos Nuevos) ...................................................... 88
C. Manejo de Logs: Registrando Eventos de tu Aplicación ......................................................... 90
C.1. ¿Por qué usar Logs? ......................................................................................................... 90
C.2. Niveles de Logging............................................................................................................ 90
C.3. Configuración Básica de Logs ........................................................................................... 91
C.4. Uso de Loggers Personalizados ........................................................................................ 92
D. Batería de Ejercicios de Python .............................................................................................. 94
Sección 1: Fundamentos (Variables, Operadores, Condicionales, Bucles) ............................. 94
1. Saludo Personalizado ...................................................................................................... 94
2. Suma de Dos Números .................................................................................................... 94
3. Número Par o Impar ........................................................................................................ 94
4. Mayor de Tres Números .................................................................................................. 95
5. Contar hasta 5 ................................................................................................................. 95
6. Cuenta Regresiva ............................................................................................................. 95
7. Tabla de Multiplicar del 7 ................................................................................................ 95
8. Suma Acumulada ............................................................................................................. 95
9. Adivina el Número ........................................................................................................... 95
10. Patrón de Asteriscos...................................................................................................... 96
Sección 2: Estructuras de Datos (Listas, Tuplas, Diccionarios, Conjuntos) ............................. 96
11. Acceder Elemento de Lista ............................................................................................ 96
Vicente Simón Rando
(CC BY-NC-ND 4.0)
7 de 115
Manual completo de Python para Principiantes
12. Añadir a Lista ................................................................................................................. 96
13. Eliminar de Lista ............................................................................................................ 97
14. Longitud de Lista ........................................................................................................... 97
15. Iterar Lista ..................................................................................................................... 97
16. Modificar Elemento de Tupla (Error Común) ................................................................ 97
17. Acceder Valor de Diccionario ........................................................................................ 97
18. Añadir a Diccionario ...................................................................................................... 97
19. Iterar Claves y Valores de Diccionario ........................................................................... 98
20. Operaciones con Conjuntos .......................................................................................... 98
Sección 3: Funciones y Alcance ............................................................................................... 98
21. Función saludar ........................................................................................................ 98
22. Función sumar_dos.................................................................................................... 98
23. Función con Valor por Defecto...................................................................................... 99
24. Alcance de Variable (Local vs Global) ............................................................................ 99
25. Función Lambda (Anónima) .......................................................................................... 99
Sección 4: Manejo de Errores y Excepciones .......................................................................... 99
26. División Segura .............................................................................................................. 99
27. Acceso a Índice Seguro ................................................................................................ 100
28. Bloque finally ........................................................................................................ 100
Sección 5: Módulos y Paquetes............................................................................................. 100
29. Usar math.pi ............................................................................................................ 100
30. Número Aleatorio con random.................................................................................. 100
31. Alias de Módulo........................................................................................................... 101
32. Importar Específico ..................................................................................................... 101
Sección 6: Trabajando con Datos Externos (Ficheros, JSON, Datetime) ............................... 101
33. Escribir en un Archivo .................................................................................................. 101
34. Leer de un Archivo ...................................................................................................... 101
35. Añadir a un Archivo ..................................................................................................... 102
Vicente Simón Rando
(CC BY-NC-ND 4.0)
8 de 115
Manual completo de Python para Principiantes
36. Leer Línea a Línea ........................................................................................................ 102
37. Guardar Diccionario como JSON ................................................................................. 102
38. Cargar JSON a Diccionario ........................................................................................... 102
39. Fecha y Hora Actual..................................................................................................... 102
40. Formatear Fecha ......................................................................................................... 103
Sección 7: Librerías Útiles (Requests, Re, Pandas) ................................................................ 103
41. Petición GET Simple con requests .......................................................................... 103
42. Extraer Emails con re ................................................................................................. 103
43. Crear DataFrame Simple con pandas ....................................................................... 103
44. Filtrar DataFrame con pandas .................................................................................. 103
Sección 8: Conceptos Adicionales (POO, Comprehensions, Generadores, CSV) .................. 104
45. Clase Animal (POO) .................................................................................................. 104
46. Herencia con Clase Perro (POO)............................................................................... 104
47. Comprensión de Listas para Pares .............................................................................. 104
48. Comprensión de Diccionarios (Precio con Impuestos)................................................ 105
49. Generador de Fibonacci .............................................................................................. 105
50. Leer y Procesar CSV Simple ......................................................................................... 105
E. Creando APIs Web con FastAPI y Uvicorn ............................................................................. 107
E.1. ¿Qué es FastAPI y por qué usarlo? ................................................................................. 107
E.2. Instalación de FastAPI y Uvicorn .................................................................................... 108
E.3. Tu Primera API: Petición GET Básica .............................................................................. 108
E.4. Petición GET con Parámetros de Ruta y Query .............................................................. 108
E.5. Petición POST: Enviando Datos al Servidor .................................................................... 109
E.6. Estructura de la Respuesta JSON.................................................................................... 110
E.7. Código Google Colab para crear el servidor ................................................................... 111
E.8. Código Google Colab para crear el cliente ..................................................................... 112
Despedida.................................................................................................................................. 115
Vicente Simón Rando
(CC BY-NC-ND 4.0)
9 de 115
Manual completo de Python para Principiantes
Vicente Simón Rando
(CC BY-NC-ND 4.0)
10 de 115
Manual completo de Python para Principiantes
1. Introducción al Mundo de Python
1.1. ¿Qué es Python y Por Qué Aprenderlo?
Python es un lenguaje de programación de alto nivel, interpretado, interactivo y
orientado a objetos. Pero, ¿qué significa todo esto en la práctica?
o
o
o
o
o
o
Fácil de Leer y Escribir (Sintaxis Clara): Una de sus mayores virtudes es su
legibilidad. Su sintaxis es muy parecida al inglés, lo que lo hace ideal para
principiantes. Menos código, más claridad.
Versátil (Propósito General): Python no está diseñado para un único propósito.
Puedes usarlo para una increíble variedad de tareas:
Desarrollo Web: Con frameworks como Django y Flask.
Análisis de Datos y Ciencia de Datos: Con librerías como Pandas, NumPy y SciPy, es
el lenguaje por excelencia para manipular y analizar grandes volúmenes de datos.
Inteligencia Artificial y Machine Learning: TensorFlow, PyTorch y Scikit-learn lo
convierten en una herramienta clave para crear modelos de IA.
Automatización de Tareas (Scripting): Ideal para automatizar procesos repetitivos en
tu ordenador, desde organizar archivos hasta enviar correos electrónicos.
Desarrollo de Software: Creación de aplicaciones de escritorio y herramientas de línea
de comandos.
Juegos: Aunque no es su fuerte, se pueden desarrollar juegos sencillos con Pygame.
Multiplataforma: Los programas escritos en Python pueden ejecutarse en diferentes
sistemas operativos (Windows, macOS, Linux) sin necesidad de ser modificados.
Gran Comunidad y Ecosistema: Cuenta con una comunidad enorme y muy activa.
Esto significa que hay miles de librerías, módulos y recursos disponibles (¡muchos de
ellos gratuitos!) para casi cualquier cosa que necesites hacer. Si tienes un problema, es
muy probable que alguien ya lo haya resuelto o que encuentres ayuda rápidamente.
En resumen, aprender Python te abre un mundo de posibilidades en el ámbito
tecnológico, especialmente si tu interés es la automatización y el análisis de datos.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
11 de 115
Manual completo de Python para Principiantes
1.2. Breve Historia y Filosofía de Python
Python fue creado a finales de los años 80 por Guido van Rossum en el Centro para las
Matemáticas y la Informática (CWI) en los Países Bajos. Su nombre no viene de la
serpiente, sino del grupo de comedia británico Monty Python.
La filosofía de Python está resumida en un documento llamado "El Zen de Python"
(puedes verlo ejecutando import this en un intérprete de Python). Algunos de sus
principios clave son:
Bello es mejor que feo.
Explícito es mejor que implícito.
Simple es mejor que complejo.
Complejo es mejor que complicado.
La legibilidad cuenta.
Estos principios buscan fomentar un código claro, conciso y fácil de entender y
mantener.
1.3. Áreas de Aplicación: de la Web a la IA
Como ya mencionamos, la versatilidad de Python es una de sus mayores fortalezas.
Aquí te doy más detalles sobre cómo se usa en la industria y cómo se alinea con tus
objetivos:
o
o
o
o
o
Automatización (Scripting): Desde simples scripts para renombrar archivos en tu
sistema operativo hasta la automatización de procesos complejos en servidores. Python
es una herramienta esencial para los administradores de sistemas y cualquier persona
que quiera optimizar su flujo de trabajo.
Análisis de Datos y Ciencia de Datos:
Recopilación y Limpieza de Datos: Importar datos de diferentes fuentes (CSV, Excel,
bases de datos, APIs), limpiarlos y prepararlos para el análisis.
Visualización de Datos: Crear gráficos y representaciones visuales para entender mejor
la información.
Análisis Estadístico: Realizar análisis complejos y modelado estadístico.
Inteligencia Artificial y Machine Learning:
Machine Learning (ML): Construir modelos que aprenden de los datos para hacer
predicciones o clasificaciones (por ejemplo, detectar spam, recomendar productos).
Deep Learning (DL): Una rama del ML que utiliza redes neuronales profundas, muy
usada en reconocimiento de imágenes y procesamiento de lenguaje natural.
Desarrollo Web (Backend): Aunque no es tu enfoque principal, es bueno saber que
empresas como Instagram, Spotify y Dropbox usan Python para sus servicios de
backend.
Finanzas, Biología, Educación, etc.: Python se está infiltrando en casi todas las
industrias gracias a su adaptabilidad y la riqueza de sus librerías.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
12 de 115
Manual completo de Python para Principiantes
1.4. Instalación de Python (Última Versión)
Para empezar a programar en Python, primero necesitamos instalarlo en nuestro
ordenador. Te recomiendo siempre trabajar con la última versión estable de Python
3.x, ya que incluye las mejoras y características más recientes.
Pasos Generales:
1. Descarga el Instalador:
o Ve a la página oficial de Python: https://www.python.org/downloads/
o El sitio web detectará tu sistema operativo (Windows, macOS, Linux) y te ofrecerá el
enlace de descarga para la última versión. Haz clic en el botón de descarga.
2. Ejecuta el Instalador:
o Windows:
Una vez descargado el .exe, haz doble clic para ejecutarlo.
¡Muy Importante! Marca la casilla "Add Python.exe to PATH" (Añadir Python.exe
al PATH) en la primera pantalla del instalador. Esto permitirá que puedas ejecutar
Python desde cualquier lugar en la línea de comandos.
Selecciona "Install Now" (Instalar ahora) para una instalación típica, o "Customize
installation" si eres un usuario avanzado (no necesario para la mayoría).
Sigue las instrucciones hasta que la instalación finalice.
o
macOS:
Descarga el .pkg y ejecútalo. Sigue los pasos del instalador. macOS a menudo viene
con una versión antigua de Python 2 preinstalada; asegúrate de que estás usando la
versión 3 que acabas de instalar.
o Linux:
La mayoría de las distribuciones de Linux ya vienen con Python preinstalado. Sin
embargo, puede que sea una versión antigua. Puedes instalar la última versión usando el
gestor de paquetes de tu distribución (por ejemplo, sudo apt install python3 en
Ubuntu/Debian o sudo dnf install python3 en Fedora/CentOS).
3. Verificar la Instalación:
o Abre una Terminal (macOS/Linux) o un Símbolo del Sistema / PowerShell
(Windows).
o Escribe el siguiente comando y presiona Enter:
Bash
python --version
o, si tienes ambas versiones instaladas y quieres asegurarte de que sea la 3:
Bash
python3 --version
o
Deberías ver la versión de Python instalada (ej: Python 3.12.3). Si ves un error, revisa
los pasos de instalación, especialmente el de añadir al PATH en Windows.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
13 de 115
Manual completo de Python para Principiantes
1.5. Configuración del Entorno de Desarrollo: VS Code
VS Code (Visual Studio Code) es un editor de código fuente: gratuito, ligero pero
potente; desarrollado por Microsoft. Es muy popular entre desarrolladores de Python
por su velocidad, su gran cantidad de extensiones y su excelente integración con
Python.
1.5.1. Instalación y Extensiones Esenciales
1. Descargar VS Code:
o Ve a la página oficial de VS Code: https://code.visualstudio.com/
o Descarga e instala la versión para tu sistema operativo. El proceso es similar al de
cualquier otra aplicación.
2. Abrir VS Code:
o Una vez instalado, ábrelo. Verás una interfaz limpia.
3. Instalar la Extensión de Python:
o En el lado izquierdo de VS Code, verás una barra de iconos. Haz clic en el icono de
Extensiones (parece un cuadrado).
o En la barra de búsqueda de extensiones, escribe Python.
o Busca la extensión oficial de "Python" de Microsoft (suele ser la primera y la más
descargada). Haz clic en el botón "Install".
o Esta extensión proporciona autocompletado, depuración, formateo de código,
integración con entornos virtuales y muchas otras funcionalidades útiles para Python.
4. Seleccionar el Intérprete de Python:
o Una vez instalada la extensión, VS Code necesita saber qué versión de Python usar.
o
o
o
Abre la Paleta de Comandos presionando Ctrl+Shift+P (Windows/Linux) o
Cmd+Shift+P (macOS).
Escribe Python: Select Interpreter y selecciona esa opción.
VS Code debería detectar las versiones de Python instaladas en tu sistema. Selecciona la
que acabas de instalar (la última versión de Python 3.x).
1.5.2. Primer "Hola Mundo" en VS Code
Vamos a escribir nuestro primer programa en Python. La tradición manda que sea un
"Hola Mundo".
1. Crear un Nuevo Archivo:
o En VS Code, ve a Archivo > Nuevo Archivo (o Ctrl+N / Cmd+N).
o Guarda el archivo inmediatamente para que VS Code lo reconozca como un archivo
Python. Ve a Archivo > Guardar Como... (o Ctrl+S / Cmd+S).
o Navega a una carpeta donde quieras guardar tus proyectos (por ejemplo, crea una
carpeta MisProyectosPython).
o Nombra el archivo hola_mundo.py. La extensión .py es crucial.
2. Escribir el Código:
o En el editor de hola_mundo.py, escribe la siguiente línea:
Python
print("¡Hola, mundo desde Python!")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
14 de 115
Manual completo de Python para Principiantes
o
Guarda el archivo (Ctrl+S / Cmd+S).
3. Ejecutar el Programa:
o Opción 1: Desde la Terminal Integrada de VS Code:
Abre la Terminal integrada en VS Code yendo a Terminal > Nueva Terminal (o
Ctrl+ñ / Cmd+ñ).
Asegúrate de que estás en la misma carpeta donde guardaste hola_mundo.py (puedes
usar cd nombre_de_la_carpeta para navegar).
Escribe el comando para ejecutar el script:
Bash
python hola_mundo.py
o
Bash
python3 hola_mundo.py
o
Deberías ver ¡Hola, mundo desde Python! impreso en la terminal.
Opción 2: Con el botón de "Run" (Ejecutar):
En la esquina superior derecha del editor de VS Code, verás un pequeño botón con un
triángulo verde (el botón de "Ejecutar"). Haz clic en él.
VS Code ejecutará el script en su terminal integrada y verás la salida.
1.6. Introducción a Google Colab
Google Colaboratory (Colab) es un servicio gratuito basado en la nube que te permite
escribir y ejecutar código Python directamente en tu navegador. Es especialmente útil
para análisis de datos, machine learning y educación, ya que no requiere
configuración local y te da acceso a hardware potente (como GPUs) de forma gratuita.
1.6.1. ¿Qué es y Cómo Funciona?
Entorno de Notebooks: Colab se basa en Jupyter Notebooks. Un notebook es un
documento interactivo que combina código ejecutable, texto enriquecido (Markdown),
ecuaciones, imágenes y visualizaciones en un solo lugar. Esto es ideal para explicar
procesos paso a paso y mostrar resultados.
Basado en la Nube: No necesitas instalar Python ni librerías en tu ordenador. Todo se
ejecuta en los servidores de Google. Solo necesitas una cuenta de Google y un
navegador web.
Acceso a GPUs/TPUs: Para tareas intensivas de machine learning, Colab ofrece acceso
gratuito a unidades de procesamiento gráfico (GPUs) y unidades de procesamiento de
tensores (TPUs), lo que acelera enormemente los cálculos.
Fácil de Compartir: Puedes compartir tus notebooks de Colab como si fueran
documentos de Google Docs, lo que facilita la colaboración.
¿Cuándo usar Colab vs. VS Code?
Vicente Simón Rando
(CC BY-NC-ND 4.0)
15 de 115
Manual completo de Python para Principiantes
VS Code: Ideal para el desarrollo de proyectos más grandes, scripts, aplicaciones, y
cuando necesitas control total sobre tu entorno local.
Google Colab: Perfecto para experimentos rápidos, análisis de datos, prototipado de
modelos de ML, tutoriales interactivos y cuando no quieres preocuparte por la
instalación de librerías.
1.6.2. Creando Nuestro Primer Notebook
1. Acceder a Google Colab:
o Abre tu navegador y ve a https://colab.research.google.com/
o Asegúrate de haber iniciado sesión con tu cuenta de Google.
2. Crear un Nuevo Notebook:
o Verás una ventana de bienvenida. Haz clic en "Archivo" > "Nuevo cuaderno" (o "New
notebook").
o
Se abrirá un nuevo notebook vacío.
3. Interfaz Básica de un Notebook:
o Un notebook se compone de celdas. Hay dos tipos principales:
Celdas de Código: Donde escribes y ejecutas código Python.
Celdas de Texto: Donde escribes texto formateado (usando Markdown) para
explicaciones, títulos, etc.
o Verás una celda de código por defecto.
4. Escribir y Ejecutar Código en una Celda:
o Haz clic en la celda de código.
o
Escribe el mismo "Hola Mundo":
Python
print("¡Hola, mundo desde Google Colab!")
o
o
Para ejecutar la celda, haz clic en el botón de "Reproducir" (triángulo) a la izquierda de
la celda, o presiona Shift + Enter.
Verás la salida debajo de la celda.
5. Añadir Celdas de Texto:
o Pasa el ratón entre dos celdas existentes o en la parte inferior del notebook. Aparecerán
botones para + Código y + Texto. Haz clic en + Texto.
o Puedes escribir Markdown en la celda de texto. Por ejemplo: # Mi Primer Notebook
de Python.
o Para renderizar el Markdown, haz clic fuera de la celda o presiona Shift + Enter.
6. Guardar el Notebook:
o Los notebooks se guardan automáticamente en tu Google Drive. Puedes cambiar el
nombre del archivo haciendo clic en el nombre en la parte superior (por defecto,
Untitled0.ipynb).
Vicente Simón Rando
(CC BY-NC-ND 4.0)
16 de 115
Manual completo de Python para Principiantes
2. Fundamentos de Programación con
Python
2.1. Conceptos Básicos: Programas, Instrucciones,
Comentarios
Para entender Python, primero aclaremos algunos términos fundamentales:
o
Programa: Un conjunto de instrucciones que un ordenador puede seguir para realizar
una tarea específica. En Python, un programa es simplemente uno o más archivos .py
que contienen código.
Instrucción (Sentencia): Es una línea de código individual que realiza una acción. Por
ejemplo, print("Hola") es una instrucción que le dice a Python que muestre el texto
"Hola" en la pantalla. Cada instrucción suele ir en una línea separada.
Comentarios: Líneas de texto dentro de tu código que Python ignora por completo. Son
vitales para explicar qué hace tu código, por qué lo hace de cierta manera o para dejar
notas para ti mismo o para otros desarrolladores. Los comentarios no afectan cómo se
ejecuta el programa, pero son cruciales para su legibilidad y mantenimiento.
Comentario de una sola línea: Se inician con el símbolo de almohadilla (#). Todo lo
que va después del # en esa línea es un comentario.
Python
# Esto es un comentario de una sola línea
print("Esto se ejecuta") # Esto es otro comentario en la misma línea
o
Comentarios de varias líneas (Docstrings): Aunque no son estrictamente
"comentarios" ignorados, se usan a menudo para documentar funciones, clases o
módulos. Se definen con triples comillas dobles o simples (""" o ''').
Python
"""
Vicente Simón Rando
(CC BY-NC-ND 4.0)
17 de 115
Manual completo de Python para Principiantes
Esto es un comentario de varias líneas,
también conocido como docstring.
Se usa para documentar bloques de código o funciones.
"""
print("El código sigue funcionando")
Ejercicio 2.1.1: Escribiendo y Comentando Código
o
o
o
o
Crea un archivo llamado conceptos_basicos.py en VS Code.
Escribe varias instrucciones print() que muestren mensajes diferentes.
Añade comentarios de una sola línea explicando cada print().
Añade un comentario de varias líneas al inicio del archivo explicando el propósito del
script.
o
Ejecuta el script. Observa que los comentarios no aparecen en la salida.
Solución 2.1.1:
Python
"""
Este script demuestra el uso de instrucciones y comentarios en Python.
Es un ejemplo básico para empezar a familiarizarse con la sintaxis.
"""
# Esta es la primera instrucción, imprime un saludo simple.
print("¡Bienvenidos al curso de Python!")
# Esta instrucción muestra un mensaje sobre la importancia de los comentarios.
print("Los comentarios hacen el código más fácil de entender.")
print("Fin del programa.") # Este comentario está al final de la línea.
2.2. Variables y Tipos de Datos Primitivos
En programación, una variable es como una caja o un contenedor con un nombre,
donde puedes guardar información. Esa información puede cambiar (variar) a lo largo
del programa.
En Python, no necesitas declarar explícitamente el tipo de dato de una variable; Python
lo infiere automáticamente.
2.2.1. Números (Enteros, Flotantes)
Python maneja diferentes tipos de números:
Enteros (int): Números completos, sin decimales (positivos, negativos o cero).
Python
edad = 30
cantidad = -100
año = 2025
Flotantes (float): Números con parte decimal.
Python
precio = 19.99
temperatura = 25.5
pi = 3.14159
Vicente Simón Rando
(CC BY-NC-ND 4.0)
18 de 115
Manual completo de Python para Principiantes
Puedes realizar operaciones aritméticas con ellos: suma (+), resta (-), multiplicación (*),
división (/), división entera (//), módulo (%), y potencia (**).
Ejercicio 2.2.1: Operaciones con Números
Crea dos variables numéricas (una entera y una flotante).
Realiza y muestra el resultado de las 5 operaciones aritméticas básicas (+, -, *, /, **)
utilizando estas variables.
Usa la función type() para mostrar el tipo de cada variable antes y después de alguna
operación si cambia.
Solución 2.2.1:
Python
numero_entero = 10
numero_flotante = 3.5
print(f"Número Entero: {numero_entero}, Tipo: {type(numero_entero)}")
print(f"Número Flotante: {numero_flotante}, Tipo: {type(numero_flotante)}")
# Suma
resultado_suma = numero_entero + numero_flotante
print(f"Suma: {resultado_suma}, Tipo: {type(resultado_suma)}") # float
# Resta
resultado_resta = numero_entero - numero_flotante
print(f"Resta: {resultado_resta}")
# Multiplicación
resultado_multiplicacion = numero_entero * numero_flotante
print(f"Multiplicación: {resultado_multiplicacion}")
# División
resultado_division = numero_entero / numero_flotante
print(f"División: {resultado_division}") # Siempre es float, incluso si el resultado es un número entero
# Potencia
resultado_potencia = numero_entero ** 2
print(f"Potencia (10^2): {resultado_potencia}")
# División entera
resultado_div_entera = numero_entero // numero_flotante
print(f"División Entera (10 // 3.5): {resultado_div_entera}, Tipo: {type(resultado_div_entera)}") # 2.0 (float)
# Módulo (resto de la división)
resultado_modulo = numero_entero % numero_flotante
print(f"Módulo (10 % 3.5): {resultado_modulo}") # 3.0
2.2.2. Cadenas de Texto (Strings)
Las cadenas de texto (str) son secuencias de caracteres (letras, números, símbolos,
espacios) encerradas entre comillas simples (') o comillas dobles ("). Python no hace
distinción entre ellas, pero es buena práctica ser consistente.
Python
nombre = "Alice"
saludo = 'Hola, ¿cómo estás?'
mensaje_largo = """Esto es un mensaje
que ocupa varias líneas."""
Puedes concatenar (unir) cadenas usando el operador + y multiplicarlas para repetirlas
(*).
Ejercicio 2.2.2: Manipulación de Cadenas
Crea dos variables de tipo cadena: tu nombre y tu apellido.
Concaténalas para formar tu nombre completo en una nueva variable.
Imprime un mensaje de bienvenida usando esta variable.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
19 de 115
Manual completo de Python para Principiantes
Crea una variable con una palabra y repítela 3 veces usando el operador de
multiplicación.
Solución 2.2.2:
Python
mi_nombre = "Juan"
mi_apellido = "Pérez"
nombre_completo = mi_nombre + " " + mi_apellido
print(f"¡Bienvenido, {nombre_completo}!")
palabra_repetir = "Python"
palabra_multiplicada = palabra_repetir * 3
print(f"Palabra repetida: {palabra_multiplicada}") # Salida: PythonPythonPython
2.2.3. Booleanos (True/False)
Los booleanos (bool) son el tipo de dato más simple, representando uno de dos valores:
True (verdadero) o False (falso). Son fundamentales para la lógica de los programas,
especialmente en las estructuras condicionales.
True y False siempre se escriben con la primera letra en mayúscula.
Python
es_mayor_edad = True
tiene_permiso = False
Ejercicio 2.2.3: Uso de Booleanos
Crea una variable booleana que indique si está lloviendo (True o False).
Crea otra variable booleana que indique si tienes un paraguas (True o False).
Imprime mensajes diferentes basándote en la combinación de estas dos variables (no
uses if todavía, solo imprime los valores y quizás una pequeña expresión).
Solución 2.2.3:
Python
esta_lloviendo = True
tengo_paraguas = False
print(f"¿Está lloviendo? {esta_lloviendo}")
print(f"¿Tengo paraguas? {tengo_paraguas}")
# Podemos ver la combinación de forma simple por ahora
print(f"¿Necesito un paraguas si llueve y no tengo? {esta_lloviendo and not tengo_paraguas}")
print(f"¿Puedo salir sin mojarme? {not esta_lloviendo or tengo_paraguas}")
2.3. Operadores
Los operadores son símbolos especiales que realizan operaciones sobre uno o más
valores (llamados operandos).
2.3.1. Aritméticos
Ya los hemos visto en la sección de números. Son para cálculos matemáticos:
Vicente Simón Rando
(CC BY-NC-ND 4.0)
20 de 115
Manual completo de Python para Principiantes
+ (Suma)
- (Resta)
* (Multiplicación)
/ (División, siempre flotante)
// (División entera)
% (Módulo, resto de la división)
** (Potencia)
2.3.2. Comparación
Se usan para comparar dos valores y siempre devuelven un valor booleano (True o
False).
== (Igual a)
!= (Diferente de)
> (Mayor que)
< (Menor que)
>= (Mayor o igual que)
<= (Menor o igual que)
Python
a = 10
b = 5
print(a == b)
print(a > b)
print(a != b)
# False
# True
# True
2.3.3. Lógicos
Se usan para combinar expresiones booleanas y también devuelven un booleano.
and (AND lógico): True si ambas expresiones son True.
or (OR lógico): True si al menos una de las expresiones es True.
not (NOT lógico): Invierte el valor booleano ( True se convierte en False, y
viceversa).
Python
es_soleado = True
es_fin_de_semana = False
print(es_soleado and es_fin_de_semana) # False (True y False)
print(es_soleado or es_fin_de_semana) # True (True o False)
print(not es_soleado)
# False
2.3.4. Asignación
Se usan para asignar valores a variables. El más común es =. También hay operadores
de asignación combinados que realizan una operación y luego asignan el resultado.
= (Asignación simple)
+= (Suma y asigna): x += 5 es equivalente a x = x + 5
-= (Resta y asigna): x -= 5 es equivalente a x = x - 5
*= (Multiplica y asigna): x *= 5 es equivalente a x = x * 5
/= (Divide y asigna): x /= 5 es equivalente a x = x / 5
Vicente Simón Rando
(CC BY-NC-ND 4.0)
21 de 115
Manual completo de Python para Principiantes
**= (Potencia y asigna), etc.
Python
x = 10
x += 5 # x ahora es 15
print(x)
y = 20
y /= 4 # y ahora es 5.0
print(y)
Ejercicio 2.3.1: Combinando Operadores
Declara dos números enteros, num1 y num2.
Usa operadores de comparación para imprimir si num1 es mayor que num2, si son
iguales, y si num1 es menor o igual que num2.
Declara dos variables booleanas, condicion1 y condicion2.
Usa operadores lógicos para imprimir el resultado de condicion1 and condicion2,
condicion1 or condicion2, y not condicion1.
Usa un operador de asignación combinado (*=) en una de las variables numéricas y
muestra el resultado.
Solución 2.3.1:
Python
num1 = 25
num2 = 15
print(f"¿{num1} es mayor que {num2}? {num1 > num2}")
print(f"¿{num1} es igual a {num2}? {num1 == num2}")
print(f"¿{num1} es menor o igual que {num2}? {num1 <= num2}")
condicion1 = True
condicion2 = False
print(f"Condicion1 AND Condicion2: {condicion1 and condicion2}")
print(f"Condicion1 OR Condicion2: {condicion1 or condicion2}")
print(f"NOT Condicion1: {not condicion1}")
valor = 7
valor *= 3 # Esto es igual a valor = valor * 3
print(f"Valor después de *=: {valor}") # Salida: 21
2.4. Entrada y Salida de Datos
Un programa no es muy útil si no puede interactuar con el usuario o mostrar resultados.
2.4.1. input(): Recoger Datos del Usuario
La función input() se usa para pedir datos al usuario desde la terminal. Siempre
devuelve lo que el usuario escribe como una cadena de texto (str), incluso si el
usuario escribe números. Si necesitas un número, deberás convertirlo.
Python
nombre_usuario = input("Por favor, introduce tu nombre: ")
print(f"Hola, {nombre_usuario}!")
# Para números, necesitas convertir:
edad_str = input("¿Cuántos años tienes? ")
edad_int = int(edad_str) # Convierte la cadena a un número entero
print(f"Tu edad es: {edad_int} años.")
# También se puede hacer directamente
altura_float = float(input("Introduce tu altura en metros: "))
Vicente Simón Rando
(CC BY-NC-ND 4.0)
22 de 115
Manual completo de Python para Principiantes
print(f"Tu altura es: {altura_float} metros.")
2.4.2. print(): Mostrar Información en Pantalla
La función print() se usa para mostrar mensajes, variables o resultados en la consola.
Puedes imprimir múltiples elementos separándolos con comas.
Python
print("Este es un mensaje.")
variable = "Python"
print("Me gusta", variable)
num1 = 5
num2 = 7
print("La suma de", num1, "y", num2, "es", num1 + num2)
2.4.3. F-Strings: Formateo de Cadenas
Las f-strings (formatted string literals) son una forma moderna y muy legible de
formatear cadenas de texto en Python 3.6+. Te permiten incrustar expresiones de
Python directamente dentro de las cadenas, precediendo la cadena con una f o F.
Python
nombre = "Ana"
edad = 28
ciudad = "Madrid"
# Sin f-strings (menos legible)
print("Hola, mi nombre es " + nombre + " y tengo " + str(edad) + " años.")
print("Hola, mi nombre es {} y tengo {} años.".format(nombre, edad)) # Usando .format()
# Con f-strings (¡mucho mejor!)
print(f"Hola, mi nombre es {nombre} y tengo {edad} años. Vivo en {ciudad}.")
# Puedes incluir expresiones directamente
producto = "Libro"
precio = 25.50
cantidad = 2
total = precio * cantidad
print(f"He comprado {cantidad} {producto}s por un total de {total:.2f} euros.") # .2f para 2 decimales
Ejercicio 2.4.1: Interacción con el Usuario y F-Strings
Pide al usuario su nombre, su año de nacimiento y su ciudad favorita.
Calcula su edad aproximada (año actual - año de nacimiento).
Utiliza una f-string para imprimir un mensaje personalizado que incluya toda esta
información (nombre, edad, ciudad favorita).
Solución 2.4.1:
Python
import datetime # Importamos el módulo datetime para obtener el año actual
nombre_usuario = input("¿Cuál es tu nombre? ")
año_nacimiento_str = input("¿En qué año naciste? ")
ciudad_favorita = input("¿Cuál es tu ciudad favorita? ")
# Convertir el año de nacimiento a entero
año_nacimiento = int(año_nacimiento_str)
# Obtener el año actual
año_actual = datetime.datetime.now().year
# Calcular edad aproximada
edad_aproximada = año_actual - año_nacimiento
# Imprimir el mensaje usando f-string
print(f"\n¡Hola, {nombre_usuario}!")
print(f"Según mis cálculos, tienes aproximadamente {edad_aproximada} años.")
print(f"¡Qué bien que te guste {ciudad_favorita}! Es una ciudad maravillosa.")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
23 de 115
Manual completo de Python para Principiantes
3. Estructuras de Control de Flujo
3.1. Estructuras Condicionales (if, elif, else)
Las estructuras condicionales nos permiten ejecutar diferentes bloques de código
basándonos en si una condición es verdadera o falsa. Piensa en ellas como las "reglas"
que sigue tu programa.
if (si): Es el bloque de código principal. Si la condición que le sigue es True, el código
dentro del if se ejecuta. Si es False, el bloque se salta.
o
Sintaxis:
Python
if condicion:
# Código que se ejecuta si la condicion es True
# ¡Importante! La indentación (espacios al inicio de la línea)
# define el bloque de código. Python usa 4 espacios estándar.
else (si no): Es opcional y se usa junto con un if. El código dentro del else se ejecuta
solo si la condición del if anterior es False.
o
Sintaxis:
Python
if condicion:
# Código si la condicion es True
else:
# Código si la condicion es False
elif (sino si): Es una contracción de "else if". Permite encadenar múltiples
condiciones. Si la condición del if es False, Python verifica la condición del primer
elif. Si esa es False, pasa al siguiente elif, y así sucesivamente. Puedes tener tantos
elif como necesites.
o
Sintaxis:
Vicente Simón Rando
(CC BY-NC-ND 4.0)
24 de 115
Manual completo de Python para Principiantes
Python
if primera_condicion:
# Código si la primera_condicion es True
elif segunda_condicion:
# Código si la segunda_condicion es True (y la primera fue False)
elif tercera_condicion:
# Código si la tercera_condicion es True (y las anteriores fueron False)
else:
# Código si ninguna de las condiciones anteriores fue True
Ejemplo de uso:
Python
edad = 17
if edad >= 18:
print("Eres mayor de edad.")
print("Puedes votar.")
else:
print("Eres menor de edad.")
print("No puedes votar todavía.")
temperatura = 25
if temperatura > 30:
print("¡Hace mucho calor!")
elif temperatura > 20: # Se ejecuta si temperatura <= 30 y temperatura > 20
print("La temperatura es agradable.")
else: # Se ejecuta si temperatura <= 20
print("Hace frío.")
Ejercicio 3.1.1: Clasificador de Notas
Pide al usuario que introduzca una nota numérica (del 0 al 100).
o
Usando if, elif y else, clasifica la nota e imprime un mensaje:
90-100: "Excelente"
o
70-89: "Notable"
o
50-69: "Aprobado"
o
0-49: "Suspendido"
Solución 3.1.1:
Python
nota_str = input("Introduce la nota (0-100): ")
nota = int(nota_str) # Convertimos la entrada a entero
if nota >= 90 and nota <= 100:
print("Excelente")
elif nota >= 70 and nota < 90:
print("Notable")
elif nota >= 50 and nota < 70:
print("Aprobado")
elif nota >= 0 and nota < 50:
print("Suspendido")
else: # Por si el usuario introduce un valor fuera del rango 0-100
print("Nota no válida. Por favor, introduce un valor entre 0 y 100.")
3.2. Estructuras Repetitivas (Bucles)
Los bucles nos permiten ejecutar un bloque de código varias veces. Esto es
increíblemente útil para tareas repetitivas o para procesar colecciones de datos.
3.2.1. for: Iteración sobre Secuencias
Vicente Simón Rando
(CC BY-NC-ND 4.0)
25 de 115
Manual completo de Python para Principiantes
El bucle for se usa para iterar sobre los elementos de una secuencia (como una cadena
de texto, una lista, una tupla, etc.). Para cada elemento de la secuencia, el código dentro
del bucle se ejecuta una vez.
Sintaxis básica:
Python
for variable_iteracion in secuencia:
# Código que se ejecuta para cada elemento en la secuencia
o
o
o
Función range(): A menudo, no queremos iterar sobre una secuencia de datos
existente, sino repetir algo un número específico de veces. Para esto, usamos la función
range().
range(n): Genera números desde 0 hasta n-1.
range(inicio, fin): Genera números desde inicio hasta fin-1.
range(inicio, fin, paso): Genera números desde inicio hasta fin-1,
incrementando por paso.
Ejemplos de for:
Python
# Iterar sobre una cadena
for letra in "Python":
print(letra)
# Iterar sobre una lista (que veremos en el próximo capítulo)
numeros = [1, 2, 3, 4, 5]
for num in numeros:
print(f"El número es: {num}")
# Usando range()
print("\nContando del 0 al 4:")
for i in range(5): # Genera 0, 1, 2, 3, 4
print(i)
print("\nContando del 1 al 5:")
for i in range(1, 6): # Genera 1, 2, 3, 4, 5
print(i)
print("\nContando de 0 a 10 de 2 en 2:")
for i in range(0, 11, 2): # Genera 0, 2, 4, 6, 8, 10
print(i)
Ejercicio 3.2.1: Tabla de Multiplicar
Pide al usuario un número.
Usa un bucle for y range() para imprimir la tabla de multiplicar de ese número del 1
al 10.
Solución 3.2.1:
Python
numero_str = input("Introduce un número para ver su tabla de multiplicar: ")
numero = int(numero_str)
print(f"Tabla de multiplicar del {numero}:")
for i in range(1, 11): # Del 1 al 10
resultado = numero * i
print(f"{numero} x {i} = {resultado}")
3.2.2. while: Bucle Condicional
El bucle while ejecuta un bloque de código repetidamente mientras una condición sea
verdadera. El bucle continuará ejecutándose hasta que la condición se evalúe como
False. Es crucial asegurarse de que la condición eventualmente se vuelva falsa para
evitar bucles infinitos.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
26 de 115
Manual completo de Python para Principiantes
Sintaxis:
Python
while condicion:
# Código que se ejecuta mientras la condicion sea True
# ¡Importante! Asegúrate de que algo dentro del bucle cambie la condición
# para que eventualmente se vuelva False y el bucle termine.
Ejemplo de uso:
Python
contador = 0
while contador < 5:
print(f"Contador: {contador}")
contador += 1 # Es vital cambiar el contador para evitar un bucle infinito
print("Bucle while terminado.")
# Bucle con validación de entrada
contraseña = ""
while contraseña != "secreto":
contraseña = input("Introduce la contraseña: ")
if contraseña != "secreto":
print("Contraseña incorrecta. Inténtalo de nuevo.")
print("¡Contraseña correcta! Acceso concedido.")
Ejercicio 3.2.2: Adivina el Número
Genera un número aleatorio entre 1 y 10 (puedes usar import random y
random.randint(1, 10)).
Usa un bucle while para pedir al usuario que adivine el número.
Da pistas al usuario ("El número es mayor" o "El número es menor") hasta que adivine
correctamente.
Cuando adivine, imprime un mensaje de felicitación y cuántos intentos le tomó.
Solución 3.2.2:
Python
import random # Importamos el módulo random
numero_secreto = random.randint(1, 10) # Genera un número entre 1 y 10 (ambos incluidos)
intento = 0
adivinado = False
numero_intentos = 0
print("Estoy pensando en un número entre 1 y 10.")
print("Intenta adivinarlo.")
while not adivinado:
intento_str = input("Introduce tu intento: ")
try: # Intentamos convertir la entrada a número (manejo básico de errores)
intento = int(intento_str)
numero_intentos += 1
if intento < numero_secreto:
print("El número es mayor. Intenta de nuevo.")
elif intento > numero_secreto:
print("El número es menor. Intenta de nuevo.")
else:
adivinado = True
print(f"¡Felicidades! Adivinaste el número {numero_secreto} en {numero_intentos} intentos.")
except ValueError:
print("Eso no es un número válido. Por favor, introduce un número.")
3.2.3. break y continue: Control de Bucles
Estas dos sentencias nos dan un control más fino sobre el comportamiento de los bucles.
break: Termina el bucle inmediatamente. La ejecución del programa continúa con la
primera instrucción después del bucle. Se usa a menudo cuando se cumple una
condición específica y no es necesario seguir iterando.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
27 de 115
Manual completo de Python para Principiantes
Python
for i in range(1, 10):
if i == 5:
print("Se encontró el 5, saliendo del bucle.")
break # El bucle se detiene aquí
print(i) # Esto se imprimirá hasta el 4
print("Fuera del bucle.")
continue: Salta el resto del código dentro de la iteración actual del bucle y pasa a la
siguiente iteración. Se usa cuando queremos omitir ciertas partes del bucle para
condiciones específicas sin salir del bucle completamente.
Python
for i in range(1, 10):
if i % 2 == 0: # Si i es un número par
print(f"Saltando número par: {i}")
continue # Salta el resto del código y va a la siguiente iteración
print(f"Número impar: {i}") # Esto solo se imprime para números impares
Ejercicio 3.2.3: Filtrado de Números
Usa un bucle for que itere del 1 al 10.
Dentro del bucle, usa continue para saltar la impresión de los números 3 y 7.
Si el número es 9, usa break para salir del bucle.
Imprime solo los números que cumplen las condiciones.
Solución 3.2.3:
Python
print("Filtrando números:")
for num in range(1, 11):
if num == 3 or num == 7:
print(f"Saltando el {num}")
continue # Pasa a la siguiente iteración sin imprimir el número
if num == 9:
print(f"¡Llegó al {num}! Saliendo del bucle.")
break # Sale del bucle completamente
print(num)
Vicente Simón Rando
(CC BY-NC-ND 4.0)
28 de 115
Manual completo de Python para Principiantes
4. Colecciones de Datos
4.1. Listas
Las listas son las colecciones más versátiles y comúnmente usadas en Python. Son
como arrays en otros lenguajes, pero con la característica de que pueden contener
elementos de diferentes tipos de datos y son mutables (pueden ser modificadas
después de su creación: añadir, eliminar o cambiar elementos).
Se definen utilizando corchetes [] y los elementos se separan por comas.
4.1.1. Creación, Acceso y Modificación
Creación:
Python
frutas = ["manzana", "banana", "cereza"]
numeros = [1, 2, 3, 4, 5]
mixta = ["hola", 10, True, 3.14]
lista_vacia = []
o
o
o
Acceso a elementos: Los elementos de una lista se acceden por su índice. En Python (y
la mayoría de los lenguajes de programación), los índices empiezan en 0.
lista[indice]: Accede al elemento en la posición indice.
Puedes usar índices negativos para acceder desde el final: -1 es el último elemento, -2
es el penúltimo, etc.
len(lista): Devuelve el número de elementos en la lista.
Python
frutas = ["manzana", "banana", "cereza", "dátil"]
print(frutas[0]) # Salida: "manzana" (primer elemento)
print(frutas[2]) # Salida: "cereza" (tercer elemento)
print(frutas[-1]) # Salida: "dátil" (último elemento)
print(len(frutas)) # Salida: 4
# Intentar acceder a un índice fuera de rango dará un error (IndexError)
# print(frutas[4])
Vicente Simón Rando
(CC BY-NC-ND 4.0)
29 de 115
Manual completo de Python para Principiantes
Modificación de elementos: Al ser mutables, puedes cambiar el valor de un elemento
específico.
Python
frutas = ["manzana", "banana", "cereza"]
frutas[1] = "arándano" # Cambia "banana" por "arándano"
print(frutas) # Salida: ["manzana", "arándano", "cereza"]
o
o
o
o
o
Slicing (Rebanado): Permite obtener una sub-lista de una lista existente.
lista[inicio:fin] : Devuelve elementos desde inicio (incluido) hasta fin
(excluido).
lista[inicio:]: Desde inicio hasta el final.
lista[:fin]: Desde el principio hasta fin (excluido).
lista[:]: Una copia completa de la lista.
lista[inicio:fin:paso]: Con un paso.
Python
numeros = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(numeros[2:5])
# Salida: [2, 3, 4]
print(numeros[7:])
# Salida: [7, 8, 9]
print(numeros[:3])
# Salida: [0, 1, 2]
print(numeros[::2])
# Salida: [0, 2, 4, 6, 8] (todos los pares)
print(numeros[::-1]) # Salida: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] (lista invertida)
4.1.2. Métodos Comunes (Añadir, Eliminar, Ordenar)
Las listas tienen muchos métodos útiles para manipularlas:
append(elemento): Añade un elemento al final de la lista.
Python
colores = ["rojo", "verde"]
colores.append("azul")
print(colores) # Salida: ["rojo", "verde", "azul"]
extend(otra_lista): Añade todos los elementos de otra lista al final de la lista actual.
Python
colores = ["rojo", "verde"]
nuevos_colores = ["azul", "amarillo"]
colores.extend(nuevos_colores)
print(colores) # Salida: ["rojo", "verde", "azul", "amarillo"]
insert(indice, elemento): Inserta un elemento en una posición específica.
Python
frutas = ["manzana", "cereza"]
frutas.insert(1, "banana") # Inserta "banana" en el índice 1
print(frutas) # Salida: ["manzana", "banana", "cereza"]
remove(elemento): Elimina la primera ocurrencia del elemento especificado. Si el
elemento no existe, da un error.
Python
frutas = ["manzana", "banana", "cereza", "banana"]
frutas.remove("banana")
print(frutas) # Salida: ["manzana", "cereza", "banana"]
Vicente Simón Rando
(CC BY-NC-ND 4.0)
30 de 115
Manual completo de Python para Principiantes
pop(indice): Elimina y devuelve el elemento en el índice especificado. Si no se
especifica el índice, elimina y devuelve el último elemento.
Python
numeros = [10, 20, 30, 40]
elemento_eliminado = numeros.pop(1) # Elimina el 20
print(numeros)
# Salida: [10, 30, 40]
print(elemento_eliminado) # Salida: 20
ultimo_elemento = numeros.pop() # Elimina el 40
print(numeros)
# Salida: [10, 30]
print(ultimo_elemento)
# Salida: 40
del lista[indice] o del lista[inicio:fin]: Elimina elementos por índice o por
slicing.
Python
mis_numeros = [1, 2, 3, 4, 5]
del mis_numeros[2] # Elimina el 3
print(mis_numeros) # Salida: [1, 2, 4, 5]
del mis_numeros[0:2] # Elimina el 1 y el 2
print(mis_numeros) # Salida: [4, 5]
clear(): Elimina todos los elementos de la lista, dejándola vacía.
Python
lista = [1, 2, 3]
lista.clear()
print(lista) # Salida: []
sort(): Ordena la lista en su lugar (modifica la lista original). Por defecto, es
ascendente.
o
o
lista.sort(reverse=True): Ordena de forma descendente.
sorted(lista): Devuelve una nueva lista ordenada sin modificar la original.
Python
puntuaciones = [85, 92, 78, 90]
puntuaciones.sort()
print(puntuaciones) # Salida: [78, 85, 90, 92]
nombres = ["Juan", "Ana", "Carlos"]
nombres.sort(reverse=True)
print(nombres) # Salida: ["Juan", "Carlos", "Ana"]
numeros_desordenados = [3, 1, 4, 2]
lista_ordenada = sorted(numeros_desordenados)
print(numeros_desordenados) # Salida: [3, 1, 4, 2] (original sin cambios)
print(lista_ordenada)
# Salida: [1, 2, 3, 4]
count(elemento): Devuelve el número de veces que un elemento aparece en la lista.
Python
letras = ['a', 'b', 'a', 'c', 'a']
print(letras.count('a')) # Salida: 3
index(elemento): Devuelve el índice de la primera ocurrencia del elemento. Si el
elemento no existe, genera un error.
Python
colores = ["rojo", "verde", "azul"]
print(colores.index("verde")) # Salida: 1
4.1.3. List Comprehensions (Introducción)
Vicente Simón Rando
(CC BY-NC-ND 4.0)
31 de 115
Manual completo de Python para Principiantes
Las List Comprehensions son una forma concisa y elegante de crear listas en Python.
Permiten construir una nueva lista aplicando una expresión a cada elemento de una
secuencia o iterable, y opcionalmente, filtrando elementos con una condición. Son muy
"pythónicas" y eficientes.
Sintaxis básica: [expresión for elemento in iterable]
Con condición: [expresión for elemento in iterable if condicion]
Python
# Crear una lista de cuadrados de números del 0 al 4
cuadrados = [x**2 for x in range(5)]
print(cuadrados) # Salida: [0, 1, 4, 9, 16]
# Crear una lista de números pares del 0 al 9
pares = [x for x in range(10) if x % 2 == 0]
print(pares) # Salida: [0, 2, 4, 6, 8]
# Convertir una lista de cadenas a mayúsculas
palabras = ["hola", "mundo", "python"]
palabras_mayusculas = [palabra.upper() for palabra in palabras]
print(palabras_mayusculas) # Salida: ['HOLA', 'MUNDO', 'PYTHON']
Ejercicio 4.1.1: Gestión de Tareas Pendientes (To-Do List)
Crea una lista inicial de tareas pendientes (por ejemplo: "Comprar pan", "Estudiar
Python", "Hacer ejercicio").
Permite al usuario:
1. Ver todas las tareas.
2. Añadir una nueva tarea.
3. Marcar una tarea como completada (eliminándola por su nombre o índice).
Usa un bucle while para que el programa se ejecute hasta que el usuario decida salir.
Implementa las opciones usando if/elif/else y los métodos de lista aprendidos.
Solución 4.1.1:
Python
tareas = ["Comprar pan", "Estudiar Python", "Hacer ejercicio"]
while True:
print("\n--- MENÚ DE TAREAS ---")
print("1. Ver tareas")
print("2. Añadir tarea")
print("3. Marcar tarea como completada")
print("4. Salir")
opcion = input("Elige una opción: ")
if opcion == '1':
if not tareas: # Si la lista está vacía
print("No tienes tareas pendientes.")
else:
print("\n--- Tus Tareas ---")
for i, tarea in enumerate(tareas): # enumerate da el índice y el elemento
print(f"{i + 1}. {tarea}")
elif opcion == '2':
nueva_tarea = input("Introduce la nueva tarea: ")
tareas.append(nueva_tarea)
print(f"'{nueva_tarea}' añadida a la lista.")
elif opcion == '3':
if not tareas:
print("No hay tareas para completar.")
continue # Vuelve al inicio del bucle
print("\n--- Tareas Actuales ---")
for i, tarea in enumerate(tareas):
print(f"{i + 1}. {tarea}")
try:
indice_a_eliminar = int(input("Introduce el número de la tarea completada: ")) - 1 # Restamos 1 porque los
índices empiezan en 0
if 0 <= indice_a_eliminar < len(tareas):
tarea_completada = tareas.pop(indice_a_eliminar)
print(f"'{tarea_completada}' marcada como completada y eliminada.")
else:
print("Número de tarea no válido.")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
32 de 115
Manual completo de Python para Principiantes
except ValueError:
print("Entrada inválida. Por favor, introduce un número.")
except IndexError:
print("Número de tarea fuera de rango.") # Aunque ya lo controlamos con el if, esto es un catch extra
elif opcion == '4':
print("¡Hasta pronto!")
break # Sale del bucle while
else:
print("Opción no válida. Por favor, elige un número del 1 al 4.")
Ejercicio 4.1.2: List Comprehension para Números Pares
Usando una List Comprehension, crea una lista que contenga solo los números pares
del 20 al 50 (ambos incluidos).
Imprime la lista resultante.
Solución 4.1.2:
Python
numeros_pares = [num for num in range(20, 51) if num % 2 == 0]
print(f"Números pares del 20 al 50: {numeros_pares}")
4.2. Tuplas
Las tuplas son similares a las listas, pero con una diferencia clave: son inmutables.
Una vez que se crea una tupla, no se pueden añadir, eliminar o modificar sus elementos.
Esto las hace útiles para datos que no deben cambiar.
Se definen utilizando paréntesis () o simplemente separando los elementos por comas.
4.2.1. Creación, Inmutabilidad y Acceso
Creación:
Python
coordenadas = (10.0, 20.5)
dias_semana = ("Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado", "Domingo")
una_tupla = (1,) # ¡Importante! Para una tupla de un solo elemento, se necesita la coma
sin_parentesis = "nombre", 30, True # También es una tupla
Inmutabilidad: Si intentas modificar un elemento, obtendrás un error.
Python
mi_tupla = (1, 2, 3)
# mi_tupla[0] = 5 # Esto daría un error: TypeError: 'tuple' object does not support item assignment
Acceso a elementos: Al igual que las listas, se accede por índice (empezando en 0) y se
puede usar slicing.
Python
colores_rgb = (255, 0, 0) # Rojo
print(colores_rgb[0]) # Salida: 255
print(colores_rgb[1:]) # Salida: (0, 0)
Usos comunes:
Vicente Simón Rando
(CC BY-NC-ND 4.0)
33 de 115
Manual completo de Python para Principiantes
o
Coordenadas geográficas (latitud, longitud).
o
Fechas (año, mes, día).
o
Valores que un método o función debe devolver y que no deberían ser alterados.
o
Como claves en diccionarios (ya que deben ser inmutables).
Ejercicio 4.2.1: Datos de un Punto
Crea una tupla llamada punto con las coordenadas (5, 10).
Intenta (y observa el error si lo haces en un IDE) cambiar la primera coordenada a 7.
Accede e imprime la segunda coordenada.
Crea una tupla de un solo elemento, por ejemplo, ("Python",).
Solución 4.2.1:
Python
punto = (5, 10)
print(f"Punto original: {punto}")
# Intentar modificar generará un TypeError (comentado para que el código funcione)
# punto[0] = 7
print(f"Segunda coordenada: {punto[1]}") # Salida: 10
tupla_singular = ("Python",)
print(f"Tupla singular: {tupla_singular}, Tipo: {type(tupla_singular)}")
# Sin la coma, sería solo un string entre paréntesis:
no_es_tupla = ("Python")
print(f"Esto NO es una tupla: {no_es_tupla}, Tipo: {type(no_es_tupla)}")
4.3. Diccionarios
Los diccionarios son colecciones desordenadas de ítems. Almacenan datos en pares de
clave-valor. Cada clave debe ser única e inmutable (como strings, números o tuplas), y
los valores pueden ser de cualquier tipo y pueden repetirse. Son ideales para representar
datos donde cada pieza de información tiene una etiqueta asociada.
Se definen utilizando llaves {}, con pares clave: valor separados por comas.
4.3.1. Creación, Acceso por Clave y Modificación
Creación:
Python
persona = {
"nombre": "Juan",
"edad": 30,
"ciudad": "Barcelona"
}
capitales = {"España": "Madrid", "Francia": "París", "Alemania": "Berlín"}
diccionario_vacio = {}
Acceso a valores: Se accede usando la clave entre corchetes.
Python
print(persona["nombre"])
# Salida: "Juan"
print(capitales["Francia"]) # Salida: "París"
Vicente Simón Rando
(CC BY-NC-ND 4.0)
34 de 115
Manual completo de Python para Principiantes
# Acceder a una clave que no existe da un error (KeyError)
# print(persona["profesion"])
# Alternativa segura: usar .get()
print(persona.get("profesion", "No especificado")) # Salida: "No especificado"
print(persona.get("edad"))
# Salida: 30
Modificación de valores: Si la clave ya existe, se actualiza su valor.
Python
persona = {"nombre": "Juan", "edad": 30}
persona["edad"] = 31 # Actualiza el valor de 'edad'
print(persona) # Salida: {'nombre': 'Juan', 'edad': 31}
Añadir nuevos pares clave-valor: Si la clave no existe, se añade un nuevo par.
Python
persona["email"] = "juan@example.com"
print(persona) # Salida: {'nombre': 'Juan', 'edad': 31, 'email': 'juan@example.com'}
4.3.2. Métodos Comunes
keys(): Devuelve una "vista" de todas las claves del diccionario.
values(): Devuelve una "vista" de todos los valores del diccionario.
items(): Devuelve una "vista" de todos los pares (clave, valor) como tuplas.
Python
dicc = {"a": 1, "b": 2, "c": 3}
print(dicc.keys())
# Salida: dict_keys(['a', 'b', 'c'])
print(dicc.values()) # Salida: dict_values([1, 2, 3])
print(dicc.items()) # Salida: dict_items([('a', 1), ('b', 2), ('c', 3)])
# Puedes convertirlos a lista si lo necesitas
print(list(dicc.keys())) # Salida: ['a', 'b', 'c']
pop(clave): Elimina el par clave-valor asociado a la clave y devuelve el valor.
del diccionario[clave]: También elimina un par clave-valor.
clear(): Vacía el diccionario.
Python
config = {"user": "admin", "pass": "1234", "level": 10}
contraseña = config.pop("pass")
print(config)
# Salida: {'user': 'admin', 'level': 10}
print(contraseña) # Salida: "1234"
del config["level"]
print(config) # Salida: {'user': 'admin'}
Iterar sobre un diccionario:
Python
productos = {"leche": 1.20, "pan": 0.80, "huevos": 2.50}
# Iterar sobre las claves (por defecto)
print("\nClaves:")
for key in productos:
print(key)
# Iterar sobre los valores
print("\nValores:")
for value in productos.values():
print(value)
# Iterar sobre clave y valor a la vez
print("\nClave-Valor:")
for key, value in productos.items():
print(f"{key}: {value} €")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
35 de 115
Manual completo de Python para Principiantes
Ejercicio 4.3.1: Agenda Telefónica Sencilla
Crea un diccionario llamado agenda con algunos contactos (nombre como clave,
número de teléfono como valor).
Permite al usuario:
1. Ver todos los contactos.
2. Añadir un nuevo contacto.
3. Buscar el número de un contacto por su nombre.
4. Eliminar un contacto.
Usa un bucle while para el menú y los métodos de diccionario adecuados.
Solución 4.3.1:
Python
agenda = {
"Ana": "123456789",
"Juan": "987654321",
"Sofía": "654123987"
}
while True:
print("\n--- AGENDA ---")
print("1. Ver todos los contactos")
print("2. Añadir contacto")
print("3. Buscar contacto")
print("4. Eliminar contacto")
print("5. Salir")
opcion = input("Elige una opción: ")
if opcion == '1':
if not agenda:
print("La agenda está vacía.")
else:
print("\n--- Contactos ---")
for nombre, telefono in agenda.items():
print(f"{nombre}: {telefono}")
elif opcion == '2':
nombre = input("Introduce el nombre del nuevo contacto: ")
if nombre in agenda:
print(f"'{nombre}' ya existe. ¿Deseas actualizar el número?")
confirmacion = input("Introduce 'si' para confirmar: ").lower()
if confirmacion == 'si':
telefono = input(f"Introduce el nuevo número para {nombre}: ")
agenda[nombre] = telefono
print(f"Número de '{nombre}' actualizado.")
else:
print("Operación cancelada.")
else:
telefono = input(f"Introduce el número de {nombre}: ")
agenda[nombre] = telefono
print(f"'{nombre}' añadido a la agenda.")
elif opcion == '3':
nombre_buscar = input("Introduce el nombre del contacto a buscar: ")
telefono_encontrado = agenda.get(nombre_buscar)
if telefono_encontrado:
print(f"El número de '{nombre_buscar}' es: {telefono_encontrado}")
else:
print(f"'{nombre_buscar}' no encontrado en la agenda.")
elif opcion == '4':
nombre_eliminar = input("Introduce el nombre del contacto a eliminar: ")
if nombre_eliminar in agenda:
del agenda[nombre_eliminar]
print(f"'{nombre_eliminar}' eliminado de la agenda.")
else:
print(f"'{nombre_eliminar}' no encontrado en la agenda.")
elif opcion == '5':
print("¡Agenda cerrada!")
break
else:
print("Opción no válida. Por favor, elige un número del 1 al 5.")
4.4. Conjuntos (Sets)
Vicente Simón Rando
(CC BY-NC-ND 4.0)
36 de 115
Manual completo de Python para Principiantes
Los conjuntos (set) son colecciones desordenadas de elementos únicos. Esto significa
que no pueden contener elementos duplicados. Son útiles para operaciones matemáticas
de conjuntos (unión, intersección, diferencia) o para eliminar duplicados de una lista.
Se definen utilizando llaves {} (como los diccionarios, pero sin pares clave-valor) o la
función set().
4.4.1. Creación y Operaciones Básicas
Creación:
Python
mi_conjunto = {1, 2, 3, 2, 1}
print(mi_conjunto) # Salida: {1, 2, 3} (los duplicados se eliminan automáticamente)
otro_conjunto = set([4, 5, 5, 6]) # Creando desde una lista
print(otro_conjunto) # Salida: {4, 5, 6}
conjunto_vacio = set() # ¡Importante! {} crea un diccionario vacío, no un conjunto vacío
Añadir elementos: add(elemento)
Python
frutas_unicas = {"manzana", "banana"}
frutas_unicas.add("cereza")
print(frutas_unicas) # Salida: {'manzana', 'banana', 'cereza'} (orden puede variar)
frutas_unicas.add("banana") # No se añade porque ya existe
print(frutas_unicas) # Salida: {'manzana', 'banana', 'cereza'}
Eliminar elementos: remove(elemento) (da error si no existe) o discard(elemento)
(no da error si no existe).
Python
numeros = {1, 2, 3, 4}
numeros.remove(3)
print(numeros) # Salida: {1, 2, 4}
numeros.discard(5) # No hace nada si 5 no está, no da error
print(numeros) # Salida: {1, 2, 4}
o
o
o
o
Operaciones de Conjuntos:
Unión: | o union() - Elementos en cualquiera de los conjuntos.
Intersección: & o intersection() - Elementos comunes a ambos conjuntos.
Diferencia: - o difference() - Elementos en el primer conjunto pero no en el
segundo.
Diferencia Simétrica: ^ o symmetric_difference() - Elementos que están en uno de
los conjuntos, pero no en ambos.
Python
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(f"Unión: {a | b}") # Salida: {1, 2, 3, 4, 5, 6}
print(f"Intersección: {a & b}") # Salida: {3, 4}
print(f"Diferencia (a - b): {a - b}") # Salida: {1, 2}
print(f"Diferencia Simétrica: {a ^ b}") # Salida: {1, 2, 5, 6}
Ejercicio 4.4.1: Números Únicos y Comunes
Crea dos conjuntos de números:
o
o
conjunto_a: del 1 al 5.
conjunto_b: del 4 al 8.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
37 de 115
Manual completo de Python para Principiantes
Imprime:
o
La unión de ambos conjuntos.
o
La intersección de ambos conjuntos.
o
Los números que están en conjunto_a pero no en conjunto_b.
Crea una lista con números duplicados (ej: [1, 2, 2, 3, 4, 4, 5]). Convierte esta
lista a un conjunto para eliminar los duplicados y luego conviértela de nuevo a una lista
para ver los números únicos.
Solución 4.4.1:
Python
conjunto_a = {1, 2, 3, 4, 5}
conjunto_b = {4, 5, 6, 7, 8}
print(f"Conjunto A: {conjunto_a}")
print(f"Conjunto B: {conjunto_b}")
print(f"Unión (A | B): {conjunto_a | conjunto_b}")
print(f"Intersección (A & B): {conjunto_a & conjunto_b}")
print(f"Diferencia (A - B): {conjunto_a - conjunto_b}")
# Eliminar duplicados de una lista
lista_con_duplicados = [1, 2, 2, 3, 4, 4, 5, 1, 6]
print(f"\nLista con duplicados: {lista_con_duplicados}")
conjunto_sin_duplicados = set(lista_con_duplicados)
print(f"Convertido a conjunto (sin duplicados, orden incierto): {conjunto_sin_duplicados}")
lista_sin_duplicados = list(conjunto_sin_duplicados)
print(f"Convertido de nuevo a lista (sin duplicados, orden original perdido): {lista_sin_duplicados}")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
38 de 115
Manual completo de Python para Principiantes
5. Funciones: Modularizando Nuestro
Código
5.1. Definición y Llamada de Funciones
Para usar una función, primero necesitamos definirla y luego llamada (o invocarla).
Definición de una Función: Se usa la palabra clave def, seguida del nombre de la
función, paréntesis (), y dos puntos :. El código dentro de la función debe estar
indentado (generalmente 4 espacios).
Python
def saludar(): # Definición de la función 'saludar'
print("¡Hola a todos!")
print("Este es un mensaje desde una función.")
.
# La función ha sido definida, pero aún no se ha ejecutado
Llamada (Invocación) de una Función: Una vez definida, para que la función se
ejecute, debes llamarla por su nombre, seguida de paréntesis.
Python
saludar() # Llamada a la función 'saludar'
# Salida:
# ¡Hola a todos!
# Este es un mensaje desde una función.
# Puedes llamarla cuantas veces quieras
saludar()
Ejercicio 5.1.1: Mi Primera Función
Define una función llamada mostrar_nombre que simplemente imprima tu nombre.
Llama a esta función tres veces.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
39 de 115
Manual completo de Python para Principiantes
Solución 5.1.1:
Python
def mostrar_nombre():
"""Esta función imprime mi nombre."""
print("Mi nombre es [Tu Nombre Aquí].")
# Llamadas a la función
mostrar_nombre()
mostrar_nombre()
mostrar_nombre()
5.2. Parámetros y Argumentos
Las funciones se vuelven mucho más útiles cuando pueden trabajar con datos que les
proporcionamos. Estos datos se pasan a través de parámetros y argumentos.
Parámetros: Son los nombres de las variables que se especifican en la definición de la
función, dentro de los paréntesis. Actúan como marcadores de posición para los datos
que la función espera recibir.
Argumentos: Son los valores reales que se pasan a la función cuando se la llama. Estos
valores se asignan a los parámetros correspondientes.
Python
def saludar_persona(nombre): # 'nombre' es un parámetro
"""Esta función saluda a una persona por su nombre."""
print(f"¡Hola, {nombre}!")
# Llamadas a la función, pasando argumentos
saludar_persona("Alicia") # "Alicia" es el argumento para el parámetro 'nombre'
saludar_persona("Pedro")
# "Pedro" es el argumento
Múltiples Parámetros: Una función puede tener varios parámetros, separados por
comas.
Python
def sumar(a, b): # 'a' y 'b' son parámetros
"""Esta función suma dos números e imprime el resultado."""
resultado = a + b
print(f"La suma de {a} y {b} es: {resultado}")
sumar(5, 3) # '5' y '3' son los argumentos
sumar(100, 25)
o
Argumentos por Posición vs. por Palabra Clave:
Posición: Los argumentos se asignan a los parámetros en el orden en que aparecen.
Python
sumar(5, 3) # 5 para 'a', 3 para 'b'
o
Palabra Clave: Puedes especificar los argumentos usando los nombres de los
parámetros, lo que permite pasar los argumentos en cualquier orden y mejora la
legibilidad.
Python
sumar(b=3, a=5) # Más explícito
Valores por Defecto para Parámetros: Puedes asignar un valor por defecto a un
parámetro en la definición de la función. Si no se proporciona un argumento para ese
parámetro al llamar a la función, se usará su valor por defecto.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
40 de 115
Manual completo de Python para Principiantes
Python
def saludar_con_idioma(nombre, idioma="espanol"):
"""Saluda a una persona en el idioma especificado o en español por defecto."""
if idioma == "espanol":
print(f"¡Hola, {nombre}!")
elif idioma == "ingles":
print(f"Hello, {nombre}!")
else:
print(f"Idioma '{idioma}' no soportado para el saludo.")
saludar_con_idioma("María")
# Usa el idioma por defecto ("espanol")
saludar_con_idioma("John", idioma="ingles") # Especifica el idioma
saludar_con_idioma("Luis", "ingles")
# También funciona por posición
Ejercicio 5.2.1: Calculadora de Área de Rectángulo
Define una función llamada calcular_area_rectangulo que acepte dos parámetros:
largo y ancho.
La función debe calcular el área e imprimir el resultado.
Llama a la función dos veces: una con argumentos posicionales y otra con argumentos
por palabra clave.
Modifica la función para que el ancho tenga un valor por defecto de 10. Prueba
llamándola solo con el largo.
Solución 5.2.1:
Python
def calcular_area_rectangulo(largo, ancho=10):
"""
Calcula y muestra el área de un rectángulo.
ancho tiene un valor por defecto de 10.
"""
area = largo * ancho
print(f"El área del rectángulo con largo {largo} y ancho {ancho} es: {area}")
# Llamadas a la función
calcular_area_rectangulo(5, 3)
# Posicional: largo=5, ancho=3
calcular_area_rectangulo(ancho=4, largo=8) # Palabra clave: largo=8, ancho=4
calcular_area_rectangulo(7)
# Usando el valor por defecto: largo=7, ancho=10
5.3. Valores de Retorno (return)
Hasta ahora, nuestras funciones solo imprimen resultados. Pero a menudo queremos que
una función calcule algo y nos devuelva ese valor para usarlo en otras partes de nuestro
programa. Para esto, usamos la palabra clave return.
Cuando una función ejecuta return, la función termina y el valor especificado después
de return es enviado de vuelta al lugar donde la función fue llamada.
Si una función no tiene una sentencia return explícita, o si return se usa sin un valor,
la función devuelve None (un valor especial en Python que significa "nada").
Python
def obtener_suma(a, b):
"""Calcula la suma de dos números y la devuelve."""
resultado = a + b
return resultado # La función devuelve el valor de 'resultado'
# Al llamar a la función, el valor devuelto se puede almacenar en una variable
suma_total = obtener_suma(10, 20)
print(f"La suma es: {suma_total}") # Salida: La suma es: 30
# Puedes usar el valor directamente en otra operación
doble_suma = obtener_suma(4, 6) * 2
print(f"El doble de la suma es: {doble_suma}") # Salida: El doble de la suma es: 20
Vicente Simón Rando
(CC BY-NC-ND 4.0)
41 de 115
Manual completo de Python para Principiantes
# Ejemplo con return sin valor explícito o sin return
def funcion_sin_retorno():
print("Esta función no devuelve nada explícitamente.")
valor = funcion_sin_retorno()
print(f"El valor devuelto es: {valor}") # Salida: El valor devuelto es: None
Retornar Múltiples Valores: En Python, una función puede devolver múltiples
valores. En realidad, devuelve una tupla de esos valores.
Python
def calcular_operaciones(num1, num2):
"""Devuelve la suma y la resta de dos números."""
suma = num1 + num2
resta = num1 - num2
return suma, resta # Esto devuelve una tupla (suma, resta)
s, r = calcular_operaciones(10, 5) # Desempaquetado de la tupla directamente
print(f"Suma: {s}, Resta: {r}") # Salida: Suma: 15, Resta: 5
resultados = calcular_operaciones(20, 7)
print(f"Resultados como tupla: {resultados}") # Salida: Resultados como tupla: (27, 13)
Ejercicio 5.3.1: Conversor de Temperatura
Define una función llamada celsius_a_fahrenheit que tome una temperatura en
Celsius como parámetro.
La función debe calcular la temperatura equivalente en Fahrenheit usando la fórmula:
F=(Ctimes9/5)+32.
La función debe devolver el valor en Fahrenheit.
Llama a la función con varias temperaturas de Celsius e imprime los resultados.
Solución 5.3.1:
Python
def celsius_a_fahrenheit(celsius):
"""
Convierte una temperatura de Celsius a Fahrenheit.
Args:
celsius (float/int): La temperatura en grados Celsius.
Returns:
float: La temperatura equivalente en grados Fahrenheit.
"""
fahrenheit = (celsius * 9/5) + 32
return fahrenheit
# Probar la función
temp_c1 = 0
temp_f1 = celsius_a_fahrenheit(temp_c1)
print(f"{temp_c1}°C son {temp_f1}°F") # Salida: 0.0°C son 32.0°F
temp_c2 = 25
temp_f2 = celsius_a_fahrenheit(temp_c2)
print(f"{temp_c2}°C son {temp_f2}°F") # Salida: 25°C son 77.0°F
temp_c3 = -10
temp_f3 = celsius_a_fahrenheit(temp_c3)
print(f"{temp_c3}°C son {temp_f3}°F") # Salida: -10°C son 14.0°F
5.4. Ámbito de las Variables (Global y Local)
El ámbito (scope) de una variable se refiere a la parte del programa donde esa variable
es accesible. Entender esto es crucial para evitar errores y escribir código predecible.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
42 de 115
Manual completo de Python para Principiantes
Variables Locales: Una variable definida dentro de una función es una variable
local. Solo es accesible desde dentro de esa función. Una vez que la función termina su
ejecución, las variables locales se destruyen.
Python
def mi_funcion():
mensaje_local = "Soy una variable local"
print(mensaje_local)
mi_funcion()
# print(mensaje_local) # Esto daría un NameError, porque mensaje_local no existe fuera de mi_funcion
Variables Globales: Una variable definida fuera de cualquier función (en el nivel
principal del script) es una variable global. Es accesible desde cualquier parte del
programa, incluyendo dentro de las funciones.
Python
saludo_global = "Hola desde fuera de la función" # Variable global
def otra_funcion():
print(saludo_global) # Acceso a la variable global
otra_funcion() # Salida: Hola desde fuera de la función
print(saludo_global) # Salida: Hola desde fuera de la función
Modificar Variables Globales desde una Función: Por defecto, una función puede
leer una variable global, pero no puede modificarla directamente (si intentas asignar
un valor a una variable con el mismo nombre dentro de la función, Python creará una
nueva variable local con ese nombre). Para modificar una variable global dentro de una
función, debes usar la palabra clave global.
Python
contador_global = 0
def incrementar_contador_incorrecto():
contador_global = 1 # Esto crea una NUEVA variable local llamada contador_global
print(f"Dentro (local): {contador_global}")
def incrementar_contador_correcto():
global contador_global # Le decimos a Python que queremos modificar la variable global
contador_global += 1
print(f"Dentro (global): {contador_global}")
print(f"Fuera (inicio): {contador_global}") # Salida: Fuera (inicio): 0
incrementar_contador_incorrecto()
print(f"Fuera (después de incorrecto): {contador_global}") # Salida: Fuera (después de incorrecto): 0 (no se modificó
la global)
incrementar_contador_correcto()
print(f"Fuera (después de correcto 1): {contador_global}") # Salida: Fuera (después de correcto 1): 1
incrementar_contador_correcto()
print(f"Fuera (después de correcto 2): {contador_global}") # Salida: Fuera (después de correcto 2): 2
o
Buena Práctica: Aunque global existe, generalmente se prefiere pasar variables
como argumentos y devolverlas como valores de retorno si necesitas modificarlas.
Esto hace que tu código sea más predecible y fácil de depurar.
Ejercicio 5.4.1: Sumador de Acumulativo Global
Define una variable global total_acumulado inicializada en 0.
Crea una función sumar_a_total que tome un número como argumento.
Dentro de la función, usa la palabra clave global para añadir el número al
total_acumulado.
Llama a la función varias veces con diferentes números.
Imprime el total_acumulado después de cada llamada y al final del script.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
43 de 115
Manual completo de Python para Principiantes
Solución 5.4.1:
Python
total_acumulado = 0 # Variable global
def sumar_a_total(numero):
"""
Suma un número al total_acumulado global.
"""
global total_acumulado # Indicamos que vamos a modificar la variable global
total_acumulado += numero
print(f"Se sumó {numero}. Total acumulado ahora: {total_acumulado}")
print(f"Total acumulado inicial: {total_acumulado}")
sumar_a_total(10) # Total: 10
sumar_a_total(5) # Total: 15
sumar_a_total(20) # Total: 35
print(f"Total acumulado final del programa: {total_acumulado}")
5.5. Funciones Lambda (Introducción)
Las funciones lambda (también llamadas funciones anónimas) son pequeñas funciones
que se definen en una sola línea y no tienen nombre. Son útiles para tareas sencillas que
solo se necesitan una vez o para pasarlas como argumentos a otras funciones.
Sintaxis: lambda argumentos: expresión
La expresión se evalúa y su resultado es el valor de retorno de la lambda.
Python
# Función normal
def duplicar(x):
return x * 2
# Función lambda equivalente
duplicar_lambda = lambda x: x * 2
print(duplicar(5))
# Salida: 10
print(duplicar_lambda(5)) # Salida: 10
# Una lambda con múltiples argumentos
sumar_lambda = lambda a, b: a + b
print(sumar_lambda(3, 7)) # Salida: 10
# Uso común: como argumento para funciones de orden superior (que toman funciones como parámetros)
# Ejemplo con sorted() para ordenar una lista de tuplas por el segundo elemento
puntos = [(1, 5), (3, 2), (2, 8)]
# sorted() ordena por el primer elemento por defecto. Queremos ordenar por el segundo.
puntos_ordenados = sorted(puntos, key=lambda punto: punto[1])
print(puntos_ordenados) # Salida: [(3, 2), (1, 5), (2, 8)]
# Ejemplo con filter() para filtrar números pares
numeros = [1, 2, 3, 4, 5, 6]
pares = list(filter(lambda x: x % 2 == 0, numeros))
print(pares) # Salida: [2, 4, 6]
Ejercicio 5.5.1: Filtrado con Lambda
Crea una lista de palabras: ["manzana", "banana", "cereza", "kiwi", "melon"].
Usa la función filter() junto con una función lambda para obtener una nueva lista
que contenga solo las palabras que tienen más de 5 letras.
Imprime la lista resultante.
Solución 5.5.1:
Python
palabras = ["manzana", "banana", "cereza", "kiwi", "melon", "naranja"]
Vicente Simón Rando
(CC BY-NC-ND 4.0)
44 de 115
Manual completo de Python para Principiantes
# Usamos filter con una lambda para seleccionar palabras con más de 5 letras
# filter() devuelve un objeto filtro, que necesitamos convertir a lista
palabras_largas = list(filter(lambda palabra: len(palabra) > 5, palabras))
print(f"Palabras originales: {palabras}")
print(f"Palabras con más de 5 letras: {palabras_largas}") # Salida: ['manzana', 'banana', 'cereza', 'naranja']
Vicente Simón Rando
(CC BY-NC-ND 4.0)
45 de 115
Manual completo de Python para Principiantes
6. Manejo de Errores y Excepciones
6.1. ¿Qué son los Errores y las Excepciones?
En Python, un error es un problema que impide que el programa se ejecute
correctamente. Hay dos tipos principales de errores:
Errores de Sintaxis (Syntax Errors): Ocurren cuando el código no sigue las reglas
gramaticales de Python. El intérprete de Python los detecta antes de ejecutar el código y
te lo indica con un SyntaxError. Estos errores impiden que el programa arranque.
Python
# Ejemplo de SyntaxError
# print("Hola mundo" # Falta un paréntesis de cierre
# if x > 5
# Falta ':'
VS Code y otros IDEs suelen marcar estos errores en tiempo real.
Excepciones (Exceptions) / Errores en Tiempo de Ejecución (Runtime Errors):
Ocurren mientras el programa se está ejecutando, incluso si la sintaxis es correcta.
Python "lanza" una excepción cuando detecta un problema que no sabe cómo manejar.
Si una excepción no se maneja, el programa se detiene abruptamente y muestra un
mensaje de error (un "traceback").
Python
# Ejemplos de excepciones comunes:
# ZeroDivisionError: Se produce al dividir un número por cero.
# print(10 / 0)
# NameError: Se produce cuando intentas usar una variable que no ha sido definida.
# print(variable_no_definida)
# TypeError: Se produce cuando una operación se aplica a un tipo de dato inapropiado.
# print("Hola" + 5)
# IndexError: Se produce al intentar acceder a un índice de lista, tupla o cadena que no existe.
# mi_lista = [1, 2, 3]
# print(mi_lista[3])
# KeyError: Se produce al intentar acceder a una clave de diccionario que no existe.
# mi_diccionario = {"a": 1}
Vicente Simón Rando
(CC BY-NC-ND 4.0)
46 de 115
Manual completo de Python para Principiantes
# print(mi_diccionario["b"])
# ValueError: Se produce cuando una función recibe un argumento de tipo correcto pero con un valor inapropiado.
# int("abc") # Intenta convertir una cadena no numérica a entero
Manejar excepciones significa anticipar estos problemas y escribir código que pueda
responder a ellos sin que el programa se caiga.
6.2. Bloques try, except, else, finally
Python proporciona una estructura específica para manejar excepciones de forma
controlada.
try: Es el bloque de código donde colocas las instrucciones que podrían generar una
excepción. Si no ocurre ninguna excepción en el bloque try, el programa continúa
normalmente. Si ocurre una, Python salta directamente al bloque except
correspondiente.
except: Este bloque se ejecuta solo si ocurre una excepción específica (o cualquier
excepción, si no se especifica ninguna) dentro del bloque try. Aquí es donde colocas el
código para manejar el error.
else (Opcional): El bloque else se ejecuta solo si NO OCURRE ninguna excepción
en el bloque try. Es útil para código que debe ejecutarse solo cuando el try ha sido
exitoso.
finally (Opcional): El bloque finally se ejecuta siempre, ocurra o no una excepción
en el bloque try. Es ideal para código de "limpieza", como cerrar archivos o conexiones
de red, que debe ejecutarse pase lo que pase.
Sintaxis General:
Python
try:
# Código que podría generar una excepción
# (por ejemplo, operación de archivo, división, conversión de tipo)
except TipoDeExcepcion1:
# Código para manejar TipoDeExcepcion1
except TipoDeExcepcion2 as e: # Puedes capturar la excepción en una variable 'e' para más detalles
# Código para manejar TipoDeExcepcion2
# print(f"Ocurrió un error: {e}")
except: # Captura cualquier otra excepción no especificada (¡usar con precaución!)
# Código para manejar otras excepciones
else:
# Código que se ejecuta SI NO HUBO excepciones en el 'try'
finally:
# Código que SIEMPRE se ejecuta, haya o no excepciones
Ejemplo de Uso:
Python
# Ejemplo 1: Manejo básico de división por cero
try:
num1 = int(input("Introduce el numerador: "))
num2 = int(input("Introduce el denominador: "))
resultado = num1 / num2
print(f"El resultado de la división es: {resultado}")
except ZeroDivisionError:
print("Error: No se puede dividir por cero.")
except ValueError:
print("Error: Has introducido un valor no numérico.")
else:
print("La división se realizó correctamente (sin errores).")
finally:
print("Bloque finally: Esto siempre se ejecuta.")
print("El programa continúa después del manejo de errores.") # Esta línea se ejecuta
Vicente Simón Rando
(CC BY-NC-ND 4.0)
47 de 115
Manual completo de Python para Principiantes
Explicación del Flujo:
1. El código dentro del try intenta ejecutarse.
2. Si ocurre un ZeroDivisionError (por ejemplo, si num2 es 0), el control salta
inmediatamente al bloque except ZeroDivisionError.
3. Si ocurre un ValueError (por ejemplo, si el usuario introduce "abc" en lugar de un
número), el control salta al bloque except ValueError.
4. Si no ocurre ninguna de estas excepciones (y no hay otras no controladas), el bloque
else se ejecuta.
5. El bloque finally siempre se ejecuta al final, independientemente de si hubo una
excepción o no.
Ejercicio 6.2.1: Conversor de Números Seguro
Pide al usuario que introduzca un número entero.
o
Usa un bloque try-except para manejar posibles errores:
Si el usuario introduce algo que no es un número entero, captura un ValueError y dile
al usuario que la entrada no es válida.
Si la conversión es exitosa, imprime el número y su tipo.
o
Asegúrate de que tu programa no se detenga si el usuario introduce una entrada
incorrecta.
Solución 6.2.1:
Python
try:
entrada = input("Introduce un número entero: ")
numero_entero = int(entrada) # Esta línea podría lanzar un ValueError
print(f"Has introducido el número: {numero_entero}")
print(f"El tipo de dato es: {type(numero_entero)}")
except ValueError:
print("Error: La entrada no es un número entero válido. Por favor, intenta de nuevo.")
except KeyboardInterrupt: # Opcional: manejar Ctrl+C
print("\nOperación cancelada por el usuario.")
else:
print("El número se procesó correctamente.")
finally:
print("Fin del intento de conversión.")
print("El flujo del programa continúa aquí.")
6.3. Tipos Comunes de Excepciones
Python tiene una jerarquía de excepciones integradas. Conocer algunas de las más
comunes te ayudará a depurar y manejar errores de manera más efectiva.
Aquí hay una lista de algunas de las excepciones más frecuentes que ya hemos
encontrado o podríamos encontrar:
SyntaxError: Como vimos, errores en la gramática de Python.
NameError: Se intenta usar un nombre (variable, función, etc.) que no está definido.
Python
variable_x + 5
Vicente Simón Rando
(CC BY-NC-ND 4.0)
48 de 115
Manual completo de Python para Principiantes
TypeError: Una operación o función se aplica a un objeto de tipo inapropiado.
Python
len(5) # len() espera una secuencia, no un entero
"hola" + [] # Sumar string y lista
ValueError: Una operación o función recibe un argumento de tipo correcto, pero con
un valor inapropiado (ej. int("hola")).
IndexError: Se intenta acceder a un índice fuera del rango de una secuencia (lista,
tupla, cadena).
Python
mi_lista = [1, 2]
mi_lista[2]
KeyError: Se intenta acceder a una clave inexistente en un diccionario.
Python
mi_dicc = {"a": 1}
mi_dicc["b"]
FileNotFoundError: Se intenta abrir un archivo que no existe. (Lo veremos en el
capítulo de Ficheros).
ZeroDivisionError: Se intenta dividir por cero.
IOError: Error de entrada/salida general, a menudo relacionado con archivos. (Engloba
FileNotFoundError en versiones antiguas, ahora es más específico).
Puedes capturar múltiples excepciones en un solo bloque except usando una tupla de
tipos de excepción:
Python
try:
valor = input("Introduce un número o un índice de lista (ej: 1 o 'texto'): ")
if valor.isdigit(): # Comprueba si es un número
num = 10 / int(valor)
print(f"Resultado de la división: {num}")
else:
mi_lista = [1, 2, 3]
print(f"Elemento en el índice {int(valor)}: {mi_lista[int(valor)]}")
except (ZeroDivisionError, ValueError, IndexError) as e:
print(f"¡Oops! Ocurrió un error: {type(e).__name__} - {e}")
except Exception as e: # Captura cualquier otra excepción no específica
print(f"Ocurrió un error inesperado: {e}")
Ejercicio 6.3.1: Simulador de Acceso a Datos Seguro
o
o
o
o
Crea una función llamada obtener_dato que reciba dos argumentos: fuente_datos
(que será un diccionario) y clave_buscada.
Dentro de la función, usa un bloque try-except para:
Intentar acceder a fuente_datos[clave_buscada].
Si la clave_buscada no existe, captura el KeyError y devuelve el mensaje "Clave no
encontrada."
Si la fuente_datos no es un diccionario (por ejemplo, si es una lista o un número),
captura el TypeError y devuelve el mensaje "Tipo de fuente de datos inválido."
Para cualquier otro error inesperado, captura Exception y devuelve "Error inesperado:
[detalle del error]".
Fuera de la función, prueba obtener_dato con diferentes escenarios (diccionario
válido, clave existente, clave inexistente, fuente de datos no válida).
Vicente Simón Rando
(CC BY-NC-ND 4.0)
49 de 115
Manual completo de Python para Principiantes
Solución 6.3.1:
Python
def obtener_dato(fuente_datos, clave_buscada):
"""
Intenta obtener un dato de una fuente de datos (diccionario) por su clave.
Maneja KeyError si la clave no existe y TypeError si la fuente no es un diccionario.
"""
try:
# Intentamos acceder al valor usando la clave
return fuente_datos[clave_buscada]
except KeyError:
# Se lanza si la clave no está en el diccionario
return "Clave no encontrada."
except TypeError:
# Se lanza si fuente_datos no soporta acceso por clave (ej. no es un diccionario)
return "Tipo de fuente de datos inválido (debe ser un diccionario)."
except Exception as e:
# Captura cualquier otra excepción inesperada
return f"Error inesperado: {e}"
# Pruebas de la función
mi_diccionario = {"nombre": "Carlos", "edad": 35, "ciudad": "Valencia"}
mi_lista = ["item1", "item2"]
un_numero = 123
print(f"Buscar 'nombre': {obtener_dato(mi_diccionario, 'nombre')}")
# Salida esperada: Carlos
print(f"Buscar 'edad': {obtener_dato(mi_diccionario, 'edad')}")
# Salida esperada: 35
print(f"Buscar 'profesion': {obtener_dato(mi_diccionario, 'profesion')}") # Salida esperada: Clave no encontrada.
print(f"Buscar en lista: {obtener_dato(mi_lista, 0)}")
# Salida esperada: Tipo de fuente de datos
inválido...
print(f"Buscar en número: {obtener_dato(un_numero, 'cualquier_cosa')}") # Salida esperada: Tipo de fuente de datos
inválido...
# Ejemplo con un caso que podría lanzar otro error (ej. operación con objeto no iterable si el diccionario fuera otra
cosa)
# Aunque aquí el TypeError ya lo captura. Este es más para ilustrar la cobertura de Exception
class MiClase:
pass
objeto_personalizado = MiClase()
print(f"Buscar en objeto personalizado: {obtener_dato(objeto_personalizado, 'alguna_clave')}") # Salida: Tipo de
fuente de datos inválido...
Vicente Simón Rando
(CC BY-NC-ND 4.0)
50 de 115
Manual completo de Python para Principiantes
7. Gestión de Módulos y Paquetes
7.1. Módulos: Organización del Código en Archivos
Un módulo en Python es simplemente un archivo .py que contiene código Python
(funciones, clases, variables, etc.). Al organizar tu código en módulos, puedes:
Reutilizar código: Escribir una función o clase una vez y usarla en diferentes
programas.
Organizar el código: Dividir un programa grande en archivos más pequeños y
manejables, cada uno con una responsabilidad específica.
Evitar conflictos de nombres: Cada módulo tiene su propio "espacio de nombres", lo
que ayuda a evitar que variables o funciones con el mismo nombre en diferentes
archivos choquen entre sí.
7.2. Importar Módulos: import
Para usar el código de un módulo en otro archivo Python, necesitas importarlo. Python
ofrece varias formas de hacerlo:
1. import nombre_modulo: Importa el módulo completo. Para acceder a sus contenidos,
debes prefijar el nombre del módulo.
Python
# archivo: mi_modulo.py
def saludar(nombre):
return f"Hola, {nombre}!"
def despedir(nombre):
return f"Adiós, {nombre}."
PI = 3.14159
Vicente Simón Rando
(CC BY-NC-ND 4.0)
51 de 115
Manual completo de Python para Principiantes
Python
# archivo: mi_programa.py
import mi_modulo
print(mi_modulo.saludar("Ana")) # Salida: Hola, Ana!
print(mi_modulo.PI)
# Salida: 3.14159
2. import nombre_modulo as alias: Importa el módulo completo pero le asigna un
alias (un nombre más corto o diferente) para facilitar su uso. Esto es muy común con
librerías populares (ej., import pandas as pd).
Python
# archivo: mi_programa.py
import mi_modulo as mm
print(mm.saludar("Pedro")) # Salida: Hola, Pedro!
3. from nombre_modulo import elemento1, elemento2: Importa solo elementos
específicos (funciones, variables, clases) de un módulo. Puedes usarlos directamente sin
el prefijo del módulo.
Python
# archivo: mi_programa.py
from mi_modulo import saludar, PI
print(saludar("María")) # Salida: Hola, María!
print(PI)
# Salida: 3.14159
# print(despedir("Juan")) # Esto daría un NameError, porque 'despedir' no fue importado
4. from nombre_modulo import *: Importa todos los elementos de un módulo.
¡Advertencia! Esto puede llevar a conflictos de nombres si importas módulos con
elementos que tienen el mismo nombre. Generalmente, no es una buena práctica en
programas grandes.
Python
# archivo: mi_programa.py
from mi_modulo import *
print(saludar("Luis"))
# Funciona
print(despedir("Elena")) # Funciona
print(PI)
# Funciona
Módulos de la Librería Estándar de Python: Python viene con una vasta librería
estándar de módulos ya preinstalados, listos para usar. Algunos ejemplos que ya
usamos o usaremos:
math: Para funciones y constantes matemáticas (math.sqrt(), math.pi).
random: Para generar números aleatorios (random.randint()).
datetime: Para trabajar con fechas y horas.
os: Para interactuar con el sistema operativo (archivos, directorios).
json: Para trabajar con datos en formato JSON.
Ejercicio 7.2.1: Uso de Módulos de la Librería Estándar
Crea un script llamado calculadora_avanzada.py.
Importa el módulo math.
Pide al usuario un número y calcula e imprime su raíz cuadrada usando math.sqrt().
Importa solo la función randint del módulo random.
Genera e imprime un número aleatorio entre 1 y 100 usando randint().
Vicente Simón Rando
(CC BY-NC-ND 4.0)
52 de 115
Manual completo de Python para Principiantes
Solución 7.2.1:
Python
# calculadora_avanzada.py
import math # Importamos el módulo math completo
from random import randint # Importamos solo la función randint
# Usando math.sqrt()
try:
num_str = input("Introduce un número para calcular su raíz cuadrada: ")
num = float(num_str)
if num >= 0:
raiz_cuadrada = math.sqrt(num)
print(f"La raíz cuadrada de {num} es: {raiz_cuadrada:.2f}") # Formatear a 2 decimales
else:
print("No se puede calcular la raíz cuadrada de un número negativo.")
except ValueError:
print("Entrada inválida. Por favor, introduce un número válido.")
# Usando randint()
numero_aleatorio = randint(1, 100) # Genera un número aleatorio entre 1 y 100
print(f"Número aleatorio generado entre 1 y 100: {numero_aleatorio}")
7.3. Paquetes: Colecciones de Módulos
A medida que los módulos se acumulan, Python permite organizarlos en paquetes. Un
paquete es básicamente una carpeta (directorio) que contiene varios módulos (archivos
.py) y, opcionalmente, subpaquetes.
La clave para que Python reconozca una carpeta como un paquete es que contenga un
archivo especial llamado __init__.py (puede estar vacío). Este archivo indica a
Python que el directorio debe tratarse como un paquete.
Estructura de un Paquete Ejemplo:
mi_proyecto/
├── main.py
└── utilidades/
├── __init__.py
├── calculos.py
└── texto.py
# Esto es un paquete
# Archivo que define 'utilidades' como un paquete
calculos.py:
Python
def sumar(a, b):
return a + b
def restar(a, b):
return a - b
texto.py:
Python
def capitalizar_primera(cadena):
return cadena.capitalize()
Importar desde Paquetes:
Para importar módulos o elementos de módulos dentro de un paquete, se usa la notación
de punto:
Python
# archivo: main.py
Vicente Simón Rando
(CC BY-NC-ND 4.0)
53 de 115
Manual completo de Python para Principiantes
# Importar un módulo completo de un paquete
import utilidades.calculos
print(utilidades.calculos.sumar(5, 3)) # Salida: 8
# Importar un módulo con alias
import utilidades.texto as ut
print(ut.capitalizar_primera("hola mundo")) # Salida: Hola mundo
# Importar un elemento específico de un módulo dentro de un paquete
from utilidades.calculos import restar
print(restar(10, 4)) # Salida: 6
7.4. El Administrador de Paquetes pip
Si bien Python tiene una librería estándar robusta, la verdadera potencia de Python
reside en su vasto ecosistema de librerías de terceros creadas por la comunidad. Estas
librerías se distribuyen como paquetes externos (o a veces simplemente "paquetes").
pip es el administrador de paquetes estándar de Python. Te permite instalar,
actualizar y desinstalar paquetes externos de forma sencilla. pip viene preinstalado con
Python 3.4 y versiones posteriores.
Instalar un paquete:
Bash
pip install nombre_del_paquete
Ejemplo: pip install requests (para hacer peticiones HTTP), pip install
pandas (para análisis de datos).
Instalar una versión específica:
Bash
pip install nombre_del_paquete==1.2.3
Actualizar un paquete:
Bash
pip install --upgrade nombre_del_paquete
Desinstalar un paquete:
Bash
pip uninstall nombre_del_paquete
Ver los paquetes instalados:
Bash
pip list
Guardar dependencias en requirements.txt: Es una buena práctica listar todos los
paquetes que tu proyecto necesita en un archivo requirements.txt.
Bash
pip freeze > requirements.txt
Vicente Simón Rando
(CC BY-NC-ND 4.0)
54 de 115
Manual completo de Python para Principiantes
Luego, otra persona (o tú en otro entorno) puede instalar todas las dependencias con:
Bash
pip install -r requirements.txt
Importante: Google Colab ya tiene muchas librerías populares preinstaladas (como
pandas, numpy, scikit-learn, tensorflow). Si necesitas una que no está, puedes
instalarla en una celda de Colab usando !pip install nombre_del_paquete. El ! le
dice a Colab que ejecute el comando como si fuera un comando de terminal.
7.5. Entornos Virtuales (Introducción Breve)
Imagina que trabajas en varios proyectos de Python, y cada uno necesita versiones
diferentes de la misma librería (por ejemplo, el Proyecto A necesita requests v2.20 y
el Proyecto B necesita requests v2.28). Si instalas todas las librerías directamente en
tu instalación global de Python, podrías tener conflictos.
Los entornos virtuales resuelven esto. Un entorno virtual es un directorio que contiene
una instalación de Python y un conjunto de librerías para un proyecto específico,
aisladas de otras instalaciones de Python. Cada proyecto puede tener su propio entorno
virtual.
Crear un entorno virtual:
Bash
python -m venv nombre_del_entorno
Esto creará una carpeta nombre_del_entorno con la copia de Python y pip para ese
entorno.
Activar el entorno virtual:
o
o
Windows (CMD/PowerShell): nombre_del_entorno\Scripts\activate
macOS/Linux (Bash/Zsh): source nombre_del_entorno/bin/activate
Una vez activado, verás el nombre del entorno entre paréntesis en tu terminal (ej.,
(nombre_del_entorno) C:\...). Ahora, cualquier pip install que hagas instalará
paquetes solo en este entorno.
Desactivar el entorno virtual:
Bash
deactivate
Aunque puede parecer un poco complejo al principio, el uso de entornos virtuales es
una práctica fundamental en el desarrollo profesional con Python para mantener los
proyectos organizados y libres de conflictos de dependencias.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
55 de 115
Manual completo de Python para Principiantes
8. Trabajando con Datos Externos
8.1. Manejo de Ficheros (Lectura y Escritura)
Interactuar con archivos es una habilidad fundamental. Nos permite almacenar datos de
forma persistente (que no se pierden al cerrar el programa) y cargar datos existentes.
¿Qué es un fichero? Es un bloque de información almacenada en un disco duro o
medio de almacenamiento, organizado en un formato específico (texto, binario, etc.).
8.1.1. Abrir, Cerrar y Modos de Apertura
Antes de poder leer o escribir en un archivo, necesitamos abrirlo. Después de usarlo, es
crucial cerrarlo para liberar los recursos del sistema y asegurar que todos los cambios
se guarden.
La función open() se usa para abrir un archivo. Toma al menos dos argumentos: la
ruta/nombre del archivo y el modo de apertura.
o
o
o
o
o
Modos de Apertura Comunes:
'r' (read): Lectura. El archivo debe existir. Si no, se lanzará un FileNotFoundError.
El puntero se coloca al principio del archivo.
'w' (write): Escritura. Si el archivo existe, su contenido se sobrescribe por completo.
Si no existe, se crea uno nuevo.
'a' (append): Añadir. Si el archivo existe, los nuevos datos se escriben al final del
archivo. Si no existe, se crea uno nuevo.
'x' (exclusive creation): Creación exclusiva. Crea un nuevo archivo. Si el archivo ya
existe, se lanzará un FileExistsError.
'b' (binary): Modo binario. Se usa para archivos no textuales (imágenes, audios). Se
combina con otros modos (ej: 'rb', 'wb').
Vicente Simón Rando
(CC BY-NC-ND 4.0)
56 de 115
Manual completo de Python para Principiantes
o
't' (text): Modo texto (por defecto). Se usa para archivos de texto. Se combina con
otros modos (ej: 'rt', 'wt').
Sintaxis:
Python
# Abrir un archivo
archivo = open("mi_archivo.txt", "r") # Abre para lectura
# ... operaciones con el archivo ...
archivo.close() # Cierra el archivo
La Sentencia with (¡Recomendada!):Para asegurar que un archivo se cierre
correctamente, incluso si ocurre un error, Python ofrece la sentencia with. Es la forma
preferida de trabajar con archivos. El archivo se cierra automáticamente al salir del
bloque with.
Python
with open("mi_archivo.txt", "r") as archivo:
# ... operaciones con el archivo (el objeto se llama 'archivo') ...
pass # placeholder, no hace nada
# El archivo se cierra automáticamente aquí
8.1.2. Lectura Línea a Línea y Completa
Una vez abierto, podemos leer el contenido del archivo.
read(): Lee todo el contenido del archivo y lo devuelve como una única cadena de
texto.
Python
with open("datos.txt", "r") as f:
contenido = f.read()
print(contenido)
readline(): Lee una sola línea del archivo cada vez. Las llamadas sucesivas leen las
siguientes líneas.
Python
with open("datos.txt", "r") as f:
linea1 = f.readline()
linea2 = f.readline()
print(f"Primera línea: {linea1.strip()}") # .strip() para eliminar saltos de línea y espacios al inicio/final
print(f"Segunda línea: {linea2.strip()}")
readlines(): Lee todas las líneas del archivo y las devuelve como una lista de
cadenas, donde cada cadena es una línea (incluyendo el salto de línea \n).
Python
with open("datos.txt", "r") as f:
lineas = f.readlines()
for linea in lineas:
print(linea.strip())
Iterar sobre el objeto archivo (¡Más eficiente!): La forma más "pythónica" y eficiente
de leer un archivo línea a línea, especialmente si es muy grande, es simplemente iterar
sobre el objeto archivo en un bucle for.
Python
# datos.txt
# Línea 1
# Línea 2
Vicente Simón Rando
(CC BY-NC-ND 4.0)
57 de 115
Manual completo de Python para Principiantes
# Línea 3
with open("datos.txt", "r") as f:
for linea in f: # f es iterable, cada iteración devuelve una línea
print(f"Leído: {linea.strip()}")
8.1.3. Escritura de Datos
Para escribir en un archivo, lo abrimos en modo 'w' (sobrescribe) o 'a' (añade) y
usamos el método write().
write(cadena): Escribe la cadena especificada en el archivo. No añade
automáticamente saltos de línea, así que debes incluirlos (\n) si los necesitas.
Python
# Escribir un archivo (sobrescribirá si existe)
with open("saludo.txt", "w") as f:
f.write("Hola, este es mi primer archivo.\n")
f.write("Estoy aprendiendo a escribir en Python.\n")
print("Archivo 'saludo.txt' creado/sobrescrito.")
# Añadir a un archivo existente
with open("saludo.txt", "a") as f:
f.write("¡Esta es una nueva línea añadida!\n")
print("Nueva línea añadida a 'saludo.txt'.")
Ejercicio 8.1.1: Gestor de Diario Sencillo
Crea un programa que permita al usuario:
1. Escribir una nueva entrada en un archivo de diario llamado mi_diario.txt. Cada
entrada debe añadir una nueva línea al archivo.
2. Ver todas las entradas del diario.
Usa un bucle while para el menú y los modos de apertura adecuados.
Asegúrate de manejar posibles IOError si el archivo no se puede abrir (aunque para
lectura/escritura básica es menos común que FileNotFoundError).
Solución 8.1.1:
Python
import datetime # Para añadir la fecha a las entradas
nombre_archivo = "mi_diario.txt"
while True:
print("\n--- GESTOR DE DIARIO ---")
print("1. Añadir nueva entrada")
print("2. Ver todas las entradas")
print("3. Salir")
opcion = input("Elige una opción: ")
if opcion == '1':
entrada = input("Escribe tu entrada de diario: ")
# Añadimos la fecha y hora a la entrada
fecha_hora = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
linea_completa = f"[{fecha_hora}] {entrada}\n"
try:
with open(nombre_archivo, "a", encoding="utf-8") as f: # Usamos encoding para caracteres especiales
f.write(linea_completa)
print("Entrada guardada correctamente.")
except IOError as e:
print(f"Error al escribir en el archivo: {e}")
elif opcion == '2':
try:
with open(nombre_archivo, "r", encoding="utf-8") as f:
print("\n--- TUS ENTRADAS DEL DIARIO ---")
contenido = f.read()
if not contenido:
print("El diario está vacío.")
else:
print(contenido.strip()) # strip para evitar líneas extra al final
except FileNotFoundError:
print("El diario aún no tiene entradas. Crea una primero.")
except IOError as e:
print(f"Error al leer el archivo: {e}")
elif opcion == '3':
print("¡Adiós!")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
58 de 115
Manual completo de Python para Principiantes
break
else:
print("Opción no válida. Intenta de nuevo.")
8.2. Persistencia de Datos con JSON
Trabajar con archivos de texto plano es útil, pero ¿qué pasa si queremos guardar datos
estructurados (como diccionarios o listas) de una manera que sea fácil de leer y escribir
por las máquinas, y también por los humanos? Aquí es donde entra JSON.
o
o
o
JSON (JavaScript Object Notation) es un formato ligero para el intercambio de datos.
Es fácil de leer y escribir para los humanos y fácil de analizar y generar para las
máquinas. Se usa mucho para APIs web y para guardar configuraciones o datos de
aplicaciones.
En Python, la estructura de JSON se mapea de forma natural a diccionarios y listas.
Objetos JSON leftrightarrow Diccionarios Python
Arrays JSON leftrightarrow Listas Python
Strings, números, booleanos, null leftrightarrow Strings, números, booleanos, None
Python
El módulo estándar de Python para trabajar con JSON es json.
8.2.1. json Módulo: Cargar y Guardar Datos Estructurados
json.dumps(objeto_python): Convierte un objeto Python (diccionario, lista, etc.) en
una cadena de texto JSON.
json.loads(cadena_json): Convierte una cadena de texto JSON en un objeto Python.
json.dump(objeto_python, archivo): Escribe un objeto Python directamente en un
archivo como JSON.
json.load(archivo): Lee datos JSON directamente de un archivo y los convierte en
un objeto Python.
Ejemplo de Uso:
Python
import json
# Datos Python (diccionario y lista)
configuracion = {
"nombre_app": "MiApp",
"version": "1.0",
"activa": True,
"usuarios": ["admin", "guest"],
"ajustes": {"tema": "oscuro", "notificaciones": True}
}
lista_productos = [
{"id": 1, "nombre": "Teclado", "precio": 45.99},
{"id": 2, "nombre": "Ratón", "precio": 20.50}
]
# 1. Convertir a cadena JSON (dumps)
json_string_config = json.dumps(configuracion, indent=4) # indent=4 para formato legible
print("--- JSON de Configuración (cadena) ---")
print(json_string_config)
# 2. Convertir de cadena JSON a Python (loads)
datos_desde_string = json.loads(json_string_config)
print("\n--- Datos cargados de cadena (Python) ---")
print(datos_desde_string['nombre_app'])
Vicente Simón Rando
(CC BY-NC-ND 4.0)
59 de 115
Manual completo de Python para Principiantes
# 3. Escribir a un archivo JSON (dump)
nombre_archivo_json = "config.json"
try:
with open(nombre_archivo_json, "w", encoding="utf-8") as f:
json.dump(configuracion, f, indent=4) # indent=4 para formato legible en el archivo
print(f"\nDatos de configuración guardados en '{nombre_archivo_json}'")
except IOError as e:
print(f"Error al guardar JSON: {e}")
# 4. Leer de un archivo JSON (load)
try:
with open(nombre_archivo_json, "r", encoding="utf-8") as f:
configuracion_cargada = json.load(f)
print(f"\nDatos cargados de '{nombre_archivo_json}' (Python) ---")
print(f"Versión de la app cargada: {configuracion_cargada['version']}")
print(f"Primer usuario: {configuracion_cargada['usuarios'][0]}")
except FileNotFoundError:
print(f"Error: El archivo '{nombre_archivo_json}' no existe.")
except json.JSONDecodeError:
print(f"Error: El archivo '{nombre_archivo_json}' no es un JSON válido.")
except IOError as e:
print(f"Error al leer JSON: {e}")
Ejercicio 8.2.1: Gestión de Contactos con JSON
Crea un programa que gestione una lista de contactos. Cada contacto será un diccionario
con "nombre", "telefono", y "email". La lista de contactos completa se guardará en
un archivo contactos.json.
Permite al usuario:
1. Añadir un nuevo contacto.
2. Ver todos los contactos.
3. Cargar contactos desde contactos.json al inicio del programa.
4. Guardar los contactos en contactos.json al salir del programa.
Asegúrate de manejar FileNotFoundError al intentar cargar el archivo si no existe,
inicializando la lista de contactos vacía en ese caso.
Solución 8.2.1:
Python
import json
NOMBRE_ARCHIVO_CONTACTOS = "contactos.json"
contactos = [] # Lista global para almacenar los contactos
def cargar_contactos():
global contactos
try:
with open(NOMBRE_ARCHIVO_CONTACTOS, "r", encoding="utf-8") as f:
contactos = json.load(f)
print(f"Contactos cargados desde '{NOMBRE_ARCHIVO_CONTACTOS}'.")
except FileNotFoundError:
print("Archivo de contactos no encontrado. Se iniciará una lista de contactos vacía.")
contactos = [] # Si no existe, inicializamos vacío
except json.JSONDecodeError:
print("Error: El archivo de contactos está corrupto. Se iniciará una lista de contactos vacía.")
contactos = []
except Exception as e:
print(f"Error inesperado al cargar contactos: {e}")
def guardar_contactos():
try:
with open(NOMBRE_ARCHIVO_CONTACTOS, "w", encoding="utf-8") as f:
json.dump(contactos, f, indent=4) # Guardar con indentación para legibilidad
print(f"Contactos guardados en '{NOMBRE_ARCHIVO_CONTACTOS}'.")
except IOError as e:
print(f"Error al guardar contactos: {e}")
def añadir_contacto():
nombre = input("Nombre del contacto: ")
telefono = input("Teléfono del contacto: ")
email = input("Email del contacto: ")
nuevo_contacto = {"nombre": nombre, "telefono": telefono, "email": email}
contactos.append(nuevo_contacto)
print("Contacto añadido.")
def ver_contactos():
if not contactos:
print("No hay contactos en la agenda.")
return
print("\n--- LISTA DE CONTACTOS ---")
for i, contacto in enumerate(contactos):
print(f"{i + 1}.")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
60 de 115
Manual completo de Python para Principiantes
print(f"
Nombre: {contacto.get('nombre', 'N/A')}")
print(f"
Teléfono: {contacto.get('telefono', 'N/A')}")
print(f"
Email: {contacto.get('email', 'N/A')}")
print("-" * 20)
# Cargar contactos al inicio del programa
cargar_contactos()
while True:
print("\n--- MENÚ DE CONTACTOS ---")
print("1. Añadir contacto")
print("2. Ver contactos")
print("3. Salir")
opcion = input("Elige una opción: ")
if opcion == '1':
añadir_contacto()
elif opcion == '2':
ver_contactos()
elif opcion == '3':
guardar_contactos() # Guardar antes de salir
print("¡Hasta la próxima!")
break
else:
print("Opción no válida. Intenta de nuevo.")
8.3. Fechas y Horas (datetime módulo)
Trabajar con fechas y horas es una tarea común en programación, desde registrar
cuándo se creó una entrada de diario hasta calcular la duración de un evento. Python
tiene el módulo estándar datetime para esto.
Objetos datetime: Combinan fecha y hora.
Objetos date: Solo fecha (año, mes, día).
Objetos time: Solo hora (hora, minuto, segundo, microsegundo).
Objetos timedelta: Representan una duración o la diferencia entre dos fechas/horas.
8.3.1. Creación, Formato y Operaciones Básicas
Importar el módulo:
Python
import datetime
Fecha y hora actuales:
Python
ahora = datetime.datetime.now()
print(f"Fecha y hora actual: {ahora}") # Ej: 2025-07-18 17:16:17.123456
hoy = datetime.date.today()
print(f"Fecha actual: {hoy}")
# Ej: 2025-07-18
Crear objetos de fecha/hora específicos:
Python
fecha_especifica = datetime.date(2023, 10, 26)
print(f"Fecha específica: {fecha_especifica}")
momento_especifico = datetime.datetime(2024, 1, 1, 10, 30, 0) # Año, mes, día, hora, min, seg
print(f"Momento específico: {momento_especifico}")
Acceder a componentes:
Vicente Simón Rando
(CC BY-NC-ND 4.0)
61 de 115
Manual completo de Python para Principiantes
Python
print(f"Año: {ahora.year}")
print(f"Mes: {ahora.month}")
print(f"Día: {ahora.day}")
print(f"Hora: {ahora.hour}")
print(f"Minuto: {ahora.minute}")
Formatear fechas y horas (strftime): Convierte un objeto datetime en una cadena
de texto con un formato específico. Usa códigos especiales (ej: %Y para año con 4
dígitos, %m para mes, %d para día, %H para hora en 24h, %M para minuto, %S para segundo,
%A para nombre del día de la semana).
Python
formato_personalizado = ahora.strftime("%d/%m/%Y %H:%M:%S")
print(f"Formato dd/mm/yyyy hh:mm:ss: {formato_personalizado}") # Ej: 18/07/2025 17:16:17
nombre_dia = ahora.strftime("%A, %d de %B del %Y")
print(f"Nombre del día: {nombre_dia}") # Ej: Friday, 18 de July del 2025 (depende de la configuración regional)
Parsear (convertir cadena a objeto datetime) (strptime): Es el inverso de
strftime. Convierte una cadena de texto en un objeto datetime o date. Debes
proporcionar el formato exacto en que está la cadena.
Python
cadena_fecha = "2023-12-25 14:30:00"
fecha_parseada = datetime.datetime.strptime(cadena_fecha, "%Y-%m-%d %H:%M:%S")
print(f"Cadena parseada: {fecha_parseada}") # Esto es un objeto datetime
print(f"Tipo: {type(fecha_parseada)}")
Operaciones con timedelta: Calcular diferencias o añadir/restar tiempo.
Python
hoy = datetime.date.today()
ayer = hoy - datetime.timedelta(days=1)
mañana = hoy + datetime.timedelta(days=1)
print(f"Ayer: {ayer}, Mañana: {mañana}")
ahora = datetime.datetime.now()
en_una_hora = ahora + datetime.timedelta(hours=1)
print(f"Ahora: {ahora.strftime('%H:%M:%S')}, En una hora: {en_una_hora.strftime('%H:%M:%S')}")
diferencia_dias = (datetime.date(2025, 12, 31) - hoy).days
print(f"Días hasta fin de año: {diferencia_dias}")
Ejercicio 8.3.1: Calculador de Edad Exacta
Pide al usuario su fecha de nacimiento (año, mes, día por separado).
Calcula su edad exacta en días.
Imprime la edad en años, meses y días, y también la edad total en días.
(Opcional) Usa un try-except para manejar ValueError si las fechas introducidas no
son válidas.
Solución 8.3.1:
Python
import datetime
try:
año_nac = int(input("Introduce tu año de nacimiento (ej: 1990): "))
mes_nac = int(input("Introduce tu mes de nacimiento (1-12): "))
dia_nac = int(input("Introduce tu día de nacimiento (1-31): "))
fecha_nacimiento = datetime.date(año_nac, mes_nac, dia_nac)
fecha_actual = datetime.date.today()
# Calcular la diferencia total en días
diferencia_dias = (fecha_actual - fecha_nacimiento).days
print(f"Has vivido un total de {diferencia_dias} días.")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
62 de 115
Manual completo de Python para Principiantes
# Calcular edad en años, meses, días (aproximado pero más intuitivo)
edad_años = fecha_actual.year - fecha_nacimiento.year
edad_meses = fecha_actual.month - fecha_nacimiento.month
edad_dias = fecha_actual.day - fecha_nacimiento.day
if edad_dias < 0:
edad_meses -= 1
# Calcular los días restantes del mes anterior
ultimo_dia_mes_anterior = (fecha_actual - datetime.timedelta(days=fecha_actual.day)).day
edad_dias += ultimo_dia_mes_anterior
if edad_meses < 0:
edad_años -= 1
edad_meses += 12
print(f"Tu edad es: {edad_años} años, {edad_meses} meses y {edad_dias} días.")
except ValueError:
print("Error: Por favor, introduce fechas válidas (números enteros para año, mes, día).")
except Exception as e:
print(f"Ocurrió un error inesperado: {e}")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
63 de 115
Manual completo de Python para Principiantes
9. Librerías Útiles y Aplicaciones
Prácticas
9.1. requests: Haciendo Peticiones HTTP (APIs Web)
Casi todas las aplicaciones modernas interactúan con servicios web a través de APIs
(Application Programming Interfaces). El módulo requests es la librería de facto en
Python para hacer peticiones HTTP, es decir, para comunicarse con servidores web,
descargar datos, enviar información, etc.
o
o
o
o
¿Qué son las peticiones HTTP? Son la forma en que los navegadores web se
comunican con los servidores web. Cuando visitas una página, tu navegador envía una
petición HTTP (GET) y el servidor responde con el contenido de la página. Las APIs
funcionan de manera similar, pero suelen intercambiar datos estructurados (como
JSON).
Métodos HTTP comunes:
GET: Solicitar datos de un servidor (ej. obtener información de un perfil, descargar una
imagen).
POST: Enviar datos a un servidor para crear un recurso (ej. registrar un nuevo usuario,
enviar un comentario).
PUT: Actualizar un recurso existente en el servidor.
DELETE: Eliminar un recurso del servidor.
9.1.1. Realizando Peticiones GET
Para obtener datos, usamos requests.get(). La respuesta del servidor se guarda en un
objeto Response.
Python
import requests
import json
Vicente Simón Rando
(CC BY-NC-ND 4.0)
64 de 115
Manual completo de Python para Principiantes
# URL de una API pública de ejemplo (datos sobre países)
url_paises = "https://restcountries.com/v3.1/name/spain"
try:
# Realizar la petición GET
respuesta = requests.get(url_paises)
# Verificar si la petición fue exitosa (código de estado 200 OK)
if respuesta.status_code == 200:
# Los datos suelen venir en formato JSON, los convertimos a un objeto Python
datos_pais = respuesta.json()
print("--- Datos de España ---")
# La API de restcountries devuelve una lista de países que coinciden
# Accedemos al primer elemento de la lista y luego a sus propiedades
if datos_pais:
print(f"Nombre Oficial: {datos_pais[0]['name']['official']}")
print(f"Capital: {datos_pais[0]['capital'][0]}")
print(f"Población: {datos_pais[0]['population']:,}") # Formato para miles
print(f"Moneda: {list(datos_pais[0]['currencies'].keys())[0]}")
else:
print("No se encontraron datos para España.")
elif respuesta.status_code == 404:
print(f"Error 404: País no encontrado en {url_paises}")
else:
print(f"Error en la petición: Código de estado {respuesta.status_code}")
except requests.exceptions.ConnectionError:
print("Error de conexión: No se pudo conectar al servidor. Verifica tu internet o la URL.")
except requests.exceptions.Timeout:
print("Error de tiempo de espera: El servidor tardó demasiado en responder.")
except requests.exceptions.RequestException as e:
print(f"Ocurrió un error inesperado al hacer la petición: {e}")
except json.JSONDecodeError:
print("Error al decodificar la respuesta JSON. El servidor no envió JSON válido.")
9.1.2. Parámetros de Consulta y Cabeceras
Parámetros de Consulta (Query Parameters): Para filtrar o especificar datos en una
petición GET, se usan parámetros en la URL (después de ?). requests permite pasarlos
como un diccionario en el argumento params.
Cabeceras (Headers): Son metadatos que se envían con la petición (ej. tipo de
contenido esperado, autenticación).
Python
import requests
# API de GitHub para buscar repositorios
url_github = "https://api.github.com/search/repositories"
# Parámetros para buscar repositorios de Python con más de 1000 estrellas
params = {
"q": "python+stars:>1000",
"sort": "stars",
"order": "desc"
}
# Puedes añadir cabeceras si la API lo requiere (ej. para autenticación o especificar formato)
headers = {
"Accept": "application/vnd.github.v3+json" # Para especificar la versión de la API de GitHub
}
try:
respuesta = requests.get(url_github, params=params, headers=headers)
respuesta.raise_for_status() # Lanza una excepción para códigos de error HTTP (4xx o 5xx)
datos_repos = respuesta.json()
print("\n--- Algunos repositorios populares de Python en GitHub ---")
for i, repo in enumerate(datos_repos['items'][:5]): # Mostrar los primeros 5
print(f"{i+1}. {repo['name']}")
print(f"
Descripción: {repo['description'][:70]}...") # Cortar descripción
print(f"
Estrellas: {repo['stargazers_count']:,}")
print(f"
URL: {repo['html_url']}\n")
except requests.exceptions.RequestException as e:
print(f"Error al conectar con GitHub API: {e}")
except json.JSONDecodeError:
print("Error al decodificar la respuesta JSON de GitHub.")
Ejercicio 9.1.1: Clima en tu Ciudad
Usa la API Open-Meteo para obtener los datos del clima de una ciudad (necesitas latitud
y longitud).
Vicente Simón Rando
(CC BY-NC-ND 4.0)
65 de 115
Manual completo de Python para Principiantes
o
o
o
Puedes obtener latitud y longitud de tu ciudad buscando "latitud longitud [nombre de la
ciudad]" en Google. Por ejemplo, para Zaragoza: 41.65 / -0.88.
La URL base de la API es https://api.open-meteo.com/v1/forecast.
Parámetros necesarios: latitude, longitude, current_weather=true.
Pide al usuario que introduzca la latitud y longitud.
Realiza la petición GET a la API.
Si la petición es exitosa, imprime la temperatura actual y la velocidad del viento.
Asegúrate de manejar posibles errores de conexión, de la API (códigos 4xx/5xx) y de
JSON.
Solución 9.1.1:
Python
import requests
import json # Necesario para manejar errores de decodificación JSON
# URL base de la API de Open-Meteo
API_URL = "https://api.open-meteo.com/v1/forecast"
print("--- CLIMA ACTUAL ---")
try:
latitud = float(input("Introduce la latitud de la ciudad (ej: 41.65 para Zaragoza): "))
longitud = float(input("Introduce la longitud de la ciudad (ej: -0.88 para Zaragoza): "))
parametros = {
"latitude": latitud,
"longitude": longitud,
"current_weather": "true" # Solicitamos los datos del clima actual
}
respuesta = requests.get(API_URL, params=parametros)
respuesta.raise_for_status() # Lanza HTTPError si la petición fue un error (4xx o 5xx)
datos_clima = respuesta.json()
# Accedemos a los datos del clima actual
if 'current_weather' in datos_clima:
temperatura = datos_clima['current_weather']['temperature']
velocidad_viento = datos_clima['current_weather']['windspeed']
print(f"\nDatos del clima en Lat: {latitud}, Lon: {longitud}")
print(f"Temperatura actual: {temperatura}°C")
print(f"Velocidad del viento: {velocidad_viento} km/h")
else:
print("No se encontraron datos de clima actual para las coordenadas proporcionadas.")
except ValueError:
print("Error: Por favor, introduce números válidos para la latitud y longitud.")
except requests.exceptions.ConnectionError:
print("Error de conexión: No se pudo conectar al servidor. Verifica tu conexión a internet.")
except requests.exceptions.Timeout:
print("Error de tiempo de espera: La petición tardó demasiado en responder.")
except requests.exceptions.HTTPError as e:
print(f"Error HTTP de la API: {e.response.status_code} - {e.response.text}")
except requests.exceptions.RequestException as e:
print(f"Ocurrió un error general de petición: {e}")
except json.JSONDecodeError:
print("Error: La respuesta de la API no es un JSON válido.")
except KeyError:
print("Error: La estructura de la respuesta JSON no es la esperada.")
9.2. re: Expresiones Regulares (Búsqueda de Patrones)
Las expresiones regulares (regex o regexp) son secuencias de caracteres que forman
un patrón de búsqueda. Son increíblemente potentes para encontrar, reemplazar o
validar texto basado en reglas complejas. El módulo estándar de Python para trabajar
con expresiones regulares es re.
¿Cuándo usarlas?
Vicente Simón Rando
(CC BY-NC-ND 4.0)
66 de 115
Manual completo de Python para Principiantes
o
Validar formatos (ej. email, número de teléfono, fecha).
o
Extraer información específica de cadenas de texto (ej. todos los números de un
documento).
o
Reemplazar texto que coincide con un patrón.
o
o
o
o
o
o
o
o
o
o
o
o
Conceptos básicos de patrones (¡muy pocos!):
.: Coincide con cualquier carácter (excepto salto de línea).
*: Coincide con 0 o más repeticiones del carácter/grupo anterior.
+: Coincide con 1 o más repeticiones del carácter/grupo anterior.
?: Coincide con 0 o 1 repetición del carácter/grupo anterior.
[abc]: Coincide con 'a' o 'b' o 'c'.
[0-9]: Coincide con cualquier dígito. \d es un atajo para esto.
[a-zA-Z]: Coincide con cualquier letra.
\s: Coincide con cualquier carácter de espacio en blanco (espacio, tab, salto de línea).
\w: Coincide con cualquier carácter de palabra (letras, números, guion bajo).
^: Inicio de la cadena.
$: Fin de la cadena.
(): Grupos para capturar partes del patrón.
9.2.1. Funciones Comunes del Módulo re
re.search(patron, cadena): Busca la primera ocurrencia del patrón en la cadena.
Devuelve un objeto Match si encuentra una coincidencia, None si no.
re.match(patron, cadena): Similar a search, pero solo busca coincidencias al
principio de la cadena.
re.findall(patron, cadena): Devuelve una lista de todas las coincidencias no
superpuestas del patrón en la cadena.
re.sub(patron, reemplazo, cadena): Reemplaza todas las ocurrencias del patrón
en la cadena con el reemplazo.
Ejemplo de Uso:
Python
import re
texto = "Mi email es test@example.com y el de mi amigo es otro.email_123@domain.org. Visita mi web: www.miweb.com"
# 1. re.search: Buscar la primera ocurrencia de un email
patron_email = r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b" # Patrón común para emails
coincidencia = re.search(patron_email, texto)
if coincidencia:
print(f"Email encontrado (search): {coincidencia.group(0)}")
# .group(0) o solo .group() devuelve la cadena que coincidió con todo el patrón.
else:
print("No se encontró ningún email.")
# 2. re.findall: Encontrar todos los emails
todos_emails = re.findall(patron_email, texto)
print(f"Todos los emails encontrados (findall): {todos_emails}")
# 3. re.sub: Reemplazar números por 'X'
texto_con_numeros = "El precio es $123.45 y tengo 7 unidades."
texto_modificado = re.sub(r"\d", "X", texto_con_numeros) # r"\d" coincide con cualquier dígito
print(f"Texto con números reemplazados: {texto_modificado}") # Salida: El precio es $XXX.XX y tengo X unidades.
# 4. re.match: Buscar al principio de la cadena
cadena_inicio = "Hola mundo"
match_hola = re.match(r"^Hola", cadena_inicio)
if match_hola:
print(f"'Hola' coincide al principio: {match_hola.group()}")
else:
print("No coincide al principio.")
match_mundo = re.match(r"mundo", cadena_inicio)
if match_mundo:
print(f"'mundo' coincide al principio: {match_mundo.group()}")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
67 de 115
Manual completo de Python para Principiantes
else:
print("'mundo' NO coincide al principio (usar search para eso).")
Ejercicio 9.2.1: Extractor de Hashtags
Dada una cadena de texto que contiene varios hashtags (palabras que empiezan con #),
como "Este es un #ejemplo de texto con #hashtags y #muchos más.".
Usa re.findall() con una expresión regular para extraer todos los hashtags
(incluyendo el #).
Imprime la lista de hashtags encontrados.
Solución 9.2.1:
Python
import re
texto_con_hashtags = "Este es un #ejemplo de texto con #hashtags, #programacion y #muchos_mas. ¡#PythonEsGenial!"
# Patrón para hashtags:
# #
-> Coincide con el carácter '#'.
# \w+
-> Coincide con uno o más caracteres de palabra (letras, números, guion bajo).
patron_hashtag = r"#\w+"
hashtags_encontrados = re.findall(patron_hashtag, texto_con_hashtags)
print(f"Texto original: '{texto_con_hashtags}'")
print(f"Hashtags encontrados: {hashtags_encontrados}") # Salida: ['#ejemplo', '#hashtags', '#programacion',
'#muchos_mas', '#PythonEsGenial']
9.3. pandas: Análisis de Datos (Introducción Muy Básica)
pandas es la librería más popular para el análisis y manipulación de datos en Python.
Es el "Excel de Python" pero mucho más potente, especialmente para grandes
volúmenes de datos. Introduce dos estructuras de datos clave:
Series: Un array unidimensional con etiquetas (un índice). Piensa en una columna de
una hoja de cálculo.
DataFrame: Una estructura de datos tabular bidimensional con etiquetas en filas y
columnas. Piensa en una hoja de cálculo completa o una tabla de base de datos.
Es una librería muy extensa, así que aquí solo haremos una introducción muy, muy
básica para mostrar su potencial.
9.3.1. Creación de DataFrames y Operaciones Básicas
Python
import pandas as pd
# 1. Crear un DataFrame desde un diccionario de listas
data = {
'Nombre': ['Ana', 'Juan', 'María', 'Pedro'],
'Edad': [28, 34, 29, 42],
'Ciudad': ['Madrid', 'Barcelona', 'Sevilla', 'Valencia'],
'Puntuacion': [85, 92, 78, 95]
}
df = pd.DataFrame(data)
print("--- DataFrame Inicial ---")
print(df)
# 2. Acceder a columnas (Series)
print("\n--- Columna 'Nombre' ---")
print(df['Nombre'])
# 3. Acceder a filas por índice (loc y iloc)
Vicente Simón Rando
(CC BY-NC-ND 4.0)
68 de 115
Manual completo de Python para Principiantes
# .loc[] para acceder por etiqueta de índice/nombre de columna
print("\n--- Fila con índice 1 (Juan) ---")
print(df.loc[1])
# .iloc[] para acceder por posición numérica (índice entero)
print("\n--- Fila en posición 2 (María) ---")
print(df.iloc[2])
# 4. Filtrar datos
print("\n--- Personas mayores de 30 años ---")
df_mayores_30 = df[df['Edad'] > 30]
print(df_mayores_30)
print("\n--- Personas de Madrid ---")
df_madrid = df[df['Ciudad'] == 'Madrid']
print(df_madrid)
# 5. Operaciones estadísticas básicas
print(f"\nEdad promedio: {df['Edad'].mean():.2f}")
print(f"Puntuación máxima: {df['Puntuacion'].max()}")
print(f"Ciudad más común:\n{df['Ciudad'].value_counts()}") # Conteo de valores únicos
Ejercicio 9.3.1: Análisis Básico de Ventas
Crea un DataFrame de pandas con los siguientes datos de ventas:
Producto: ['Laptop', 'Ratón', 'Teclado', 'Monitor', 'Cámara']
Cantidad: [10, 50, 30, 15, 25]
Precio_Unitario: [1200, 25, 75, 300, 150]
Imprime el Total_Ventas promedio de todos los productos.
Filtra e imprime solo los productos cuyo Total_Ventas sea mayor a $2000.
Calcula una nueva columna llamada Total_Ventas (Cantidad * Precio_Unitario).
Imprime el DataFrame con la nueva columna.
Solución 9.3.1:
Python
import pandas as pd
datos_ventas = {
'Producto': ['Laptop', 'Ratón', 'Teclado', 'Monitor', 'Cámara'],
'Cantidad': [10, 50, 30, 15, 25],
'Precio_Unitario': [1200, 25, 75, 300, 150]
}
df_ventas = pd.DataFrame(datos_ventas)
print("--- DataFrame de Ventas Inicial ---")
print(df_ventas)
# Calcular la nueva columna 'Total_Ventas'
df_ventas['Total_Ventas'] = df_ventas['Cantidad'] * df_ventas['Precio_Unitario']
print("\n--- DataFrame con Total_Ventas ---")
print(df_ventas)
# Calcular el Total_Ventas promedio
promedio_ventas = df_ventas['Total_Ventas'].mean()
print(f"\nTotal de ventas promedio: ${promedio_ventas:.2f}")
# Filtrar productos con Total_Ventas mayor a 2000
productos_grandes = df_ventas[df_ventas['Total_Ventas'] > 2000]
print("\n--- Productos con Total de Ventas > $2000 ---")
print(productos_grandes)
Vicente Simón Rando
(CC BY-NC-ND 4.0)
69 de 115
Manual completo de Python para Principiantes
10. ¡Creando y Ejecutando Tu Primer
Proyecto Completo!
10.1. Planificación del Proyecto: "Gestor de Contactos
Avanzado"
Vamos a crear una versión más robusta de nuestro "Gestor de Contactos", pero esta vez
lo haremos como un proyecto multi-archivo, usando JSON para la persistencia, con
manejo de errores y un menú de usuario.
Requisitos del Proyecto:
1. Modularidad: Dividir el código en al menos dos archivos (.py):
o main.py: Contendrá el bucle principal del programa y el menú de interacción con el
usuario.
o contact_manager.py: Contendrá todas las funciones relacionadas con la lógica de
gestionar contactos (añadir, ver, guardar, cargar, etc.).
2. Persistencia: Los contactos se guardarán y cargarán desde un archivo JSON
(contactos.json).
3. Funcionalidades:
o Cargar Contactos: Al iniciar el programa, intentará cargar los contactos desde
contactos.json. Si el archivo no existe o está corrupto, la lista de contactos
comenzará vacía.
o Añadir Contacto: Solicitará nombre, teléfono y email, y añadirá el nuevo contacto a la
lista.
o Ver Contactos: Mostrará todos los contactos numerados.
o Buscar Contacto: Permitirá buscar un contacto por nombre y mostrará sus detalles.
o Eliminar Contacto: Permitirá eliminar un contacto por su número en la lista.
o Guardar Contactos: Antes de salir, los contactos actuales se guardarán en
contactos.json.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
70 de 115
Manual completo de Python para Principiantes
o
Salir: Terminará el programa.
4. Manejo de Errores: Implementar try-except para:
o FileNotFoundError o json.JSONDecodeError al cargar el archivo.
o ValueError si el usuario introduce un número de opción o índice inválido.
o Posibles errores de índice al eliminar contactos.
10.2. Estructura del Proyecto
Crea una nueva carpeta para el proyecto, por ejemplo, gestor_contactos_pro. Dentro
de ella, crea los siguientes archivos:
gestor_contactos_pro/
├── main.py
├── contact_manager.py
└── contactos.json (se creará automáticamente la primera vez)
10.3. Implementación Paso a Paso
Paso 1: Archivo contact_manager.py (Lógica de Negocio)
Este archivo contendrá las funciones principales para manipular la lista de contactos.
Python
# contact_manager.py
import json
CONTACTS_FILE = "contactos.json" # Nombre del archivo JSON
def load_contacts():
"""
Carga los contactos desde el archivo JSON.
Retorna una lista de diccionarios de contactos.
"""
try:
with open(CONTACTS_FILE, "r", encoding="utf-8") as f:
contacts = json.load(f)
print(f"✔️ Contactos cargados desde '{CONTACTS_FILE}'.")
return contacts
except FileNotFoundError:
print(f"⚠️ Archivo '{CONTACTS_FILE}' no encontrado. Iniciando con lista de contactos vacía.")
return []
except json.JSONDecodeError:
print(f"❌ Error al decodificar JSON en '{CONTACTS_FILE}'. Archivo corrupto. Iniciando con lista vacía.")
return []
except Exception as e:
print(f"❌ Error inesperado al cargar contactos: {e}. Iniciando con lista vacía.")
return []
def save_contacts(contacts):
"""
Guarda la lista de contactos en el archivo JSON.
"""
try:
with open(CONTACTS_FILE, "w", encoding="utf-8") as f:
json.dump(contacts, f, indent=4) # Guardar con indentación para legibilidad
print(f"✔️ Contactos guardados en '{CONTACTS_FILE}'.")
except IOError as e:
print(f"❌ Error al guardar contactos: {e}")
except Exception as e:
print(f"❌ Error inesperado al guardar contactos: {e}")
def add_contact(contacts):
"""
Solicita al usuario los detalles de un nuevo contacto y lo añade a la lista.
"""
name = input("Nombre del contacto: ")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
71 de 115
Manual completo de Python para Principiantes
phone = input("Teléfono del contacto: ")
email = input("Email del contacto: ")
# Opcional: Validar si el contacto ya existe (por nombre)
for contact in contacts:
if contact["nombre"].lower() == name.lower():
print(f"⚠️ El contacto '{name}' ya existe. Considera actualizarlo o usar un nombre diferente.")
return
new_contact = {"nombre": name, "telefono": phone, "email": email}
contacts.append(new_contact)
print(f"✅ Contacto '{name}' añadido correctamente.")
def view_contacts(contacts):
"""
Muestra todos los contactos numerados.
"""
if not contacts:
print("ℹ️ No hay contactos en la agenda.")
return
print("\n--- LISTA DE CONTACTOS ---")
for i, contact in enumerate(contacts):
print(f"Contacto #{i + 1}:")
print(f" Nombre: {contact.get('nombre', 'N/A')}")
print(f" Teléfono: {contact.get('telefono', 'N/A')}")
print(f" Email: {contact.get('email', 'N/A')}")
print("-" * 30)
def search_contact(contacts):
"""
Busca un contacto por nombre y muestra sus detalles.
"""
search_name = input("Introduce el nombre del contacto a buscar: ")
found = False
for contact in contacts:
# Búsqueda insensible a mayúsculas/minúsculas
if search_name.lower() in contact["nombre"].lower():
print("\n--- CONTACTO ENCONTRADO ---")
print(f" Nombre: {contact.get('nombre', 'N/A')}")
print(f" Teléfono: {contact.get('telefono', 'N/A')}")
print(f" Email: {contact.get('email', 'N/A')}")
found = True
break # Asumimos que queremos el primer resultado coincidente
if not found:
print(f"ℹ️ No se encontró ningún contacto que contenga '{search_name}'.")
def delete_contact(contacts):
"""
Elimina un contacto por su número en la lista.
"""
if not contacts:
print("ℹ️ No hay contactos para eliminar.")
return
view_contacts(contacts) # Mostrar contactos para que el usuario elija
try:
index_to_delete = int(input("Introduce el NÚMERO del contacto a eliminar: ")) - 1 # Ajustar a índice 0-based
if 0 <= index_to_delete < len(contacts):
removed_contact = contacts.pop(index_to_delete)
print(f"✅ Contacto '{removed_contact.get('nombre', 'N/A')}' eliminado correctamente.")
else:
print("⚠️ Número de contacto no válido. Fuera de rango.")
except ValueError:
print("❌ Entrada inválida. Por favor, introduce un número.")
except Exception as e:
print(f"❌ Ocurrió un error inesperado al eliminar el contacto: {e}")
Paso 2: Archivo main.py (Lógica de Interfaz y Ejecución)
Este archivo importará las funciones de contact_manager.py y contendrá el bucle
principal del programa que gestiona el menú.
Python
# main.py
import contact_manager # Importa nuestro módulo de gestión de contactos
def display_menu():
"""Muestra el menú de opciones al usuario."""
print("\n--- MENÚ PRINCIPAL DEL GESTOR DE CONTACTOS ---")
print("1. Añadir nuevo contacto")
print("2. Ver todos los contactos")
print("3. Buscar contacto por nombre")
print("4. Eliminar contacto")
print("5. Salir")
print("---------------------------------------------")
def main():
"""Función principal que ejecuta el gestor de contactos."""
# Cargar contactos al inicio del programa
contacts = contact_manager.load_contacts()
Vicente Simón Rando
(CC BY-NC-ND 4.0)
72 de 115
Manual completo de Python para Principiantes
while True:
display_menu()
choice = input("Elige una opción (1-5): ")
if choice == '1':
contact_manager.add_contact(contacts)
elif choice == '2':
contact_manager.view_contacts(contacts)
elif choice == '3':
contact_manager.search_contact(contacts)
elif choice == '4':
contact_manager.delete_contact(contacts)
elif choice == '5':
contact_manager.save_contacts(contacts) # Guardar contactos antes de salir
print("👋 ¡Gracias por usar el Gestor de Contactos! Hasta pronto.")
break
else:
print("⚠️ Opción no válida. Por favor, introduce un número del 1 al 5.")
# Punto de entrada del programa
if __name__ == "__main__":
main()
10.4. Cómo Ejecutar el Proyecto
1. Guarda los archivos: Asegúrate de que main.py y contact_manager.py estén en la
misma carpeta (gestor_contactos_pro).
2. Abre una terminal/línea de comandos: Navega hasta la carpeta
gestor_contactos_pro usando el comando cd.
Bash
cd ruta/a/tu/carpeta/gestor_contactos_pro
3. Ejecuta el programa:
Bash
python main.py
El programa se iniciará, cargará los contactos (o creará un archivo contactos.json
vacío si no existe), mostrará el menú y esperará tus comandos.
10.5. Repaso y Consejos para Proyectos
Al crear este proyecto, has aplicado casi todos los conceptos vistos:
Variables y Tipos de Datos: Para los contactos, nombres, números, etc.
Estructuras de Control: if/elif/else para el menú, for para iterar contactos, while
para el bucle principal.
Funciones: Hemos definido funciones con parámetros para cada operación.
Colecciones: Listas (contacts) y Diccionarios (cada contact).
Manejo de Errores: Bloques try-except para archivos e inputs.
Módulos: Hemos dividido el programa en main.py y contact_manager.py, usando
import.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
73 de 115
Manual completo de Python para Principiantes
Manejo de Ficheros y JSON: Para guardar y cargar la lista de contactos de forma
persistente.
Consejos para tus futuros proyectos:
1. Divide y Vencerás: Descompón problemas grandes en funciones más pequeñas y
módulos.
2. Nombres Claros: Usa nombres de variables y funciones descriptivos.
3. Comentarios (cuando sea necesario): Explica el "porqué" de tu código, no solo el
"qué".
4. Prueba tu Código: Ejecuta tus funciones con diferentes entradas para asegurarte de que
funcionen como esperas.
5. Reutilización: Si necesitas hacer algo similar en varias partes, considera convertirlo en
una función.
6. Control de Versiones (Git): Para proyectos más grandes, aprende a usar Git. Es
esencial para colaborar y gestionar cambios en el código.
7. ¡No te rindas! La programación es un proceso de aprendizaje continuo y resolución de
problemas.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
74 de 115
Manual completo de Python para Principiantes
A. Conceptos Adicionales Clave
A.1. Programación Orientada a Objetos (POO)
La Programación Orientada a Objetos (POO, o OOP por sus siglas en inglés) es un
paradigma de programación, una forma de pensar y estructurar tu código. En lugar de
centrarte solo en funciones que operan sobre datos, la POO se centra en crear "objetos"
que encapsulan tanto datos (atributos) como las funciones que operan sobre esos datos
(métodos).
Piensa en los objetos del mundo real: un coche tiene atributos (color, modelo,
velocidad) y puede realizar acciones (acelerar, frenar). En POO, modelamos esto en
nuestro código.
A.1.1. Clases y Objetos
o
o
Clase: Es como un plano, una plantilla o una receta para crear objetos. Define la
estructura (qué atributos tendrá) y el comportamiento (qué métodos podrá hacer) que
todos los objetos de ese tipo compartirán. Una clase no ocupa memoria por sí misma; es
solo la definición.
Ejemplo: La clase Coche podría definir que todos los coches tienen color, modelo y
pueden acelerar().
Objeto (Instancia): Es una realización concreta de una clase. Cuando creas un objeto
a partir de una clase, estás creando una "instancia" de esa clase. Cada objeto tiene sus
propios valores para los atributos definidos en la clase.
Ejemplo: mi_coche = Coche("rojo", "Sedan") crea un objeto específico de la clase
Coche, con su propio color "rojo" y modelo "Sedan". otro_coche = Coche("azul",
"SUV") sería otro objeto distinto.
A.1.2. Atributos y Métodos
Vicente Simón Rando
(CC BY-NC-ND 4.0)
75 de 115
Manual completo de Python para Principiantes
Dentro de una clase, definimos:
o
o
Atributos: Son las variables que pertenecen a una clase o a un objeto. Representan las
características o datos que el objeto almacena.
Ejemplo: En la clase Coche, color y modelo serían atributos.
Métodos: Son las funciones que pertenecen a una clase. Representan las acciones o
comportamientos que los objetos de esa clase pueden realizar. Los métodos siempre
tienen un primer parámetro llamado self.
Ejemplo: En la clase Coche, acelerar() y frenar() serían métodos.
A.1.3. self
El parámetro self es una convención en Python y siempre es el primer parámetro de
cualquier método de instancia. Cuando llamas a un método de un objeto (ej.
mi_coche.acelerar()), Python automáticamente pasa el propio objeto (mi_coche en
este caso) como el primer argumento al método. Este argumento se "captura" en el
parámetro self.
self permite al método acceder a los atributos y otros métodos del objeto en el que se
está llamando. Es cómo el objeto se "refiere a sí mismo".
Python
class Coche:
# Este es el constructor (método especial __init__)
# Se llama automáticamente cuando creas un nuevo objeto Coche
def __init__(self, color, modelo):
# 'self.color' y 'self.modelo' son atributos del objeto que se está creando
self.color = color
self.modelo = modelo
self.velocidad = 0 # Atributo con valor inicial por defecto
# Método para acelerar el coche
def acelerar(self, incremento):
self.velocidad += incremento # Modificamos el atributo 'velocidad' del objeto
print(f"El {self.modelo} {self.color} acelera. Nueva velocidad: {self.velocidad} km/h")
# Método para frenar el coche
def frenar(self, decremento):
self.velocidad = max(0, self.velocidad - decremento) # Aseguramos que la velocidad no sea negativa
print(f"El {self.modelo} {self.color} frena. Nueva velocidad: {self.velocidad} km/h")
# Método especial para representación de cadena
# Se llama cuando usas print() con el objeto o str()
def __str__(self):
return f"Coche {self.modelo} (Color: {self.color}, Velocidad actual: {self.velocidad} km/h)"
# --- Creación de Objetos (Instancias) --mi_coche = Coche("azul", "Sedan") # Se llama automáticamente a __init__
otro_coche = Coche("rojo", "SUV")
# --- Uso de Atributos y Métodos --print(mi_coche) # Llama a __str__
print(otro_coche)
mi_coche.acelerar(50)
otro_coche.acelerar(30)
otro_coche.acelerar(20)
mi_coche.frenar(10)
otro_coche.frenar(60) # Frena completamente el SUV
A.1.4. Constructores (__init__)
El método __init__ (con doble guion bajo al principio y al final) es un método especial
en Python llamado constructor.
Se ejecuta automáticamente cada vez que creas una nueva instancia (objeto) de la
clase.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
76 de 115
Manual completo de Python para Principiantes
Su propósito principal es inicializar los atributos del nuevo objeto con los valores que
le pasas al crear la instancia.
Siempre recibe self como primer parámetro, seguido de los parámetros que necesites
para inicializar los atributos.
A.1.5. Herencia
La herencia es un pilar fundamental de la POO. Permite que una clase (la clase hija o
subclase) herede atributos y métodos de otra clase (la clase padre o superclase). Esto
fomenta la reutilización de código y la creación de una jerarquía lógica.
La clase hija puede:
o
Usar los atributos y métodos de la clase padre directamente.
o
Añadir sus propios atributos y métodos.
o
Sobrescribir (modificar) el comportamiento de los métodos heredados.
Python
class Vehiculo: # Clase Padre/Superclase
def __init__(self, marca, modelo):
self.marca = marca
self.modelo = modelo
self.en_movimiento = False
def arrancar(self):
if not self.en_movimiento:
self.en_movimiento = True
print(f"El {self.marca} {self.modelo} ha arrancado.")
else:
print(f"El {self.marca} {self.modelo} ya estaba en movimiento.")
def detener(self):
if self.en_movimiento:
self.en_movimiento = False
print(f"El {self.marca} {self.modelo} se ha detenido.")
else:
print(f"El {self.marca} {self.modelo} ya estaba detenido.")
def __str__(self):
return f"Vehículo: {self.marca} {self.modelo}"
class Coche(Vehiculo): # Clase Hija/Subclase: Hereda de Vehiculo
def __init__(self, marca, modelo, num_puertas):
# Llamar al constructor de la clase padre para inicializar sus atributos
super().__init__(marca, modelo)
self.num_puertas = num_puertas # Atributo propio de Coche
def tocar_bocina(self): # Método propio de Coche
print(f"El {self.marca} {self.modelo} hace '¡BEEP BEEP!'")
# Sobreescribir el método __str__ para añadir más detalles
def __str__(self):
return f"Coche: {self.marca} {self.modelo} ({self.num_puertas} puertas)"
class Motocicleta(Vehiculo): # Otra clase Hija que hereda de Vehiculo
def __init__(self, marca, modelo, tipo_moto):
super().__init__(marca, modelo)
self.tipo_moto = tipo_moto
def hacer_caballito(self): # Método propio de Motocicleta
print(f"La {self.marca} {self.modelo} ({self.tipo_moto}) está haciendo un caballito... ¡cuidado!")
# --- Uso de la Herencia --mi_coche = Coche("Ford", "Focus", 4)
mi_moto = Motocicleta("Honda", "CBR500R", "Deportiva")
print(mi_coche)
print(mi_moto)
mi_coche.arrancar()
mi_coche.tocar_bocina()
mi_coche.detener()
# Método heredado de Vehiculo
# Método propio de Coche
# Método heredado de Vehiculo
mi_moto.arrancar()
# Método heredado de Vehiculo
mi_moto.hacer_caballito() # Método propio de Motocicleta
A.1.6. Polimorfismo
Vicente Simón Rando
(CC BY-NC-ND 4.0)
77 de 115
Manual completo de Python para Principiantes
El polimorfismo significa "muchas formas". En POO, se refiere a la capacidad de
diferentes objetos de responder a un mismo mensaje (llamada a un método) de una
manera específica según su propia clase. Esto se logra a menudo a través de la herencia
y la sobrescritura de métodos.
Si tienes un método con el mismo nombre en diferentes clases (especialmente en una
jerarquía de herencia), puedes llamar a ese método en objetos de diferentes clases, y
cada objeto ejecutará su propia implementación de ese método.
Python
# Reutilizando las clases Vehiculo, Coche, Motocicleta de arriba
def describir_vehiculo(vehiculo):
"""Función que acepta cualquier objeto que sea un Vehiculo (o subclase de Vehiculo)."""
print(f"Descripción: {vehiculo}") # Llama al __str__ específico de cada objeto
vehiculo.arrancar() # Llama al método arrancar() de cada objeto
# Si quisieras, aquí podrías añadir lógica específica:
# if isinstance(vehiculo, Coche):
#
vehiculo.tocar_bocina()
print("\n--- Demostración de Polimorfismo ---")
describir_vehiculo(mi_coche)
describir_vehiculo(mi_moto)
# Incluso con un objeto de la clase base
mi_bicicleta = Vehiculo("Generica", "Bici Urbana")
describir_vehiculo(mi_bicicleta)
Observa cómo la misma función describir_vehiculo puede operar con objetos de
tipo Coche, Motocicleta o Vehiculo, y el método __str__ o arrancar() ejecutado
es el específico de cada tipo de objeto.
A.1.7. Encapsulamiento
El encapsulamiento se refiere a agrupar los datos (atributos) y los métodos que operan
sobre esos datos dentro de una única unidad (la clase). También implica restringir el
acceso directo a algunos de los componentes del objeto, protegiendo los datos internos
de manipulaciones externas no deseadas.
En Python, el encapsulamiento se maneja principalmente por convención:
Atributos Públicos: Son accesibles y modificables directamente desde fuera de la
clase. (self.atributo_publico).
Atributos Protegidos (convención): Prefijados con un solo guion bajo (_). Indican que
el atributo está destinado a uso interno de la clase o sus subclases, pero no hay una
restricción técnica para accederlo desde fuera.
Atributos Privados (convención y "name mangling"): Prefijados con dos guiones
bajos (__). Python "renombra" estos atributos internamente para hacer más difícil su
acceso directo desde fuera de la clase, pero no imposible
(_Clase__atributo_privado). Esto evita conflictos de nombres en herencia.
La forma recomendada de interactuar con atributos internos es a través de métodos
públicos (llamados "getters" y "setters" en otros lenguajes, aunque en Python no
siempre se usan así explícitamente).
Python
class CuentaBancariaSegura:
def __init__(self, numero_cuenta, titular, saldo_inicial=0.0):
self.__numero_cuenta = numero_cuenta # Atributo "privado"
self.__titular = titular
# Atributo "privado"
self.__saldo = saldo_inicial
# Atributo "privado"
Vicente Simón Rando
(CC BY-NC-ND 4.0)
78 de 115
Manual completo de Python para Principiantes
# Método getter para el saldo
def get_saldo(self):
return self.__saldo
# Método setter para depositar (con validación)
def depositar(self, cantidad):
if cantidad > 0:
self.__saldo += cantidad
print(f"Depósito de {cantidad:.2f}€. Nuevo saldo: {self.__saldo:.2f}€")
else:
print("Cantidad a depositar debe ser positiva.")
# Método setter para retirar (con validación)
def retirar(self, cantidad):
if cantidad > 0 and self.__saldo >= cantidad:
self.__saldo -= cantidad
print(f"Retiro de {cantidad:.2f}€. Nuevo saldo: {self.__saldo:.2f}€")
elif cantidad <= 0:
print("Cantidad a retirar debe ser positiva.")
else:
print("Saldo insuficiente.")
def __str__(self):
# Accedemos a los atributos internos desde dentro de la clase
return f"Cuenta {self.__numero_cuenta} de {self.__titular}. Saldo: {self.__saldo:.2f}€"
# --- Uso de la clase con encapsulamiento --mi_cuenta = CuentaBancariaSegura("12345", "Alice Smith", 100.0)
print(mi_cuenta) # Llama a __str__
mi_cuenta.depositar(50)
mi_cuenta.retirar(20)
mi_cuenta.retirar(200) # Intentar retirar más de lo que hay
# Intentar acceder directamente al atributo "privado" (desaconsejado y dificil)
# print(mi_cuenta.__saldo) # Esto daría un AttributeError
print(f"Saldo consultado con getter: {mi_cuenta.get_saldo()}€") # Forma correcta de acceder
A.2. Comprensión de Listas, Diccionarios y Conjuntos
(Comprehensions)
Las "comprehensions" son una característica muy poderosa y concisa de Python para
crear nuevas secuencias (listas, diccionarios, conjuntos) a partir de otras secuencias. Son
una forma más legible y, a menudo, más eficiente que usar un bucle for tradicional con
un append.
Piensa en ellas como una forma compacta de aplicar un filtro y una transformación a
una colección existente.
A.2.1. Comprensión de Listas (List Comprehensions)
La forma más común y ampliamente utilizada. La sintaxis básica es:
[expresion for elemento in iterable if condicion]
expresion: Lo que quieres que se evalúe para cada elemento (el valor que irá en la
nueva lista).
elemento: La variable que toma cada valor del iterable.
iterable: La secuencia (lista, tupla, cadena, rango, etc.) sobre la que vas a iterar.
if condicion (opcional): Un filtro. Si la condición es True, el elemento se incluye; si
es False, se omite.
Ejemplos:
Vicente Simón Rando
(CC BY-NC-ND 4.0)
79 de 115
Manual completo de Python para Principiantes
Python
# 1. Crear una lista de cuadrados de números del 0 al 4
cuadrados = []
for i in range(5):
cuadrados.append(i**2)
print(f"Cuadrados (bucle for): {cuadrados}")
cuadrados_comp = [i**2 for i in range(5)]
print(f"Cuadrados (list comprehension): {cuadrados_comp}")
# 2. Filtrar solo los números pares de una lista
numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
pares = [num for num in numeros if num % 2 == 0]
print(f"Números pares: {pares}")
# 3. Transformar y filtrar al mismo tiempo (duplicar solo los impares)
duplicados_impares = [num * 2 for num in numeros if num % 2 != 0]
print(f"Duplicados de impares: {duplicados_impares}")
# 4. Comprensión anidada (útil para aplanar listas de listas)
matriz = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
aplanada = [num for fila in matriz for num in fila]
print(f"Matriz aplanada: {aplanada}")
# 5. Con una expresión condicional (if-else dentro de la expresión)
# Si es par, duplicar; si es impar, dejar como está
transformados = [num * 2 if num % 2 == 0 else num for num in numeros]
print(f"Números transformados: {transformados}")
A.2.2. Comprensión de Diccionarios (Dict Comprehensions)
Permite crear diccionarios de forma concisa. La sintaxis es similar, pero especificando
clave: valor:
{clave_expresion: valor_expresion for elemento in iterable if
condicion}
Ejemplos:
Python
# 1. Crear un diccionario de cuadrados
numeros = [1, 2, 3, 4, 5]
dicc_cuadrados = {num: num**2 for num in numeros}
print(f"Diccionario de cuadrados: {dicc_cuadrados}")
# 2. Invertir un diccionario (claves por valores)
capitales = {"España": "Madrid", "Francia": "París", "Alemania": "Berlín"}
capitales_invertido = {valor: clave for clave, valor in capitales.items()}
print(f"Capitales invertido: {capitales_invertido}")
# 3. Filtrar y crear un nuevo diccionario
productos = {"manzana": 1.2, "banana": 0.5, "cereza": 3.0, "dátil": 2.5}
productos_caros = {nombre: precio for nombre, precio in productos.items() if precio > 1.0}
print(f"Productos caros: {productos_caros}")
A.2.3. Comprensión de Conjuntos (Set Comprehensions)
Funciona igual que la comprensión de listas, pero genera un conjunto (garantizando
elementos únicos y sin orden). Usa llaves {}.
{expresion for elemento in iterable if condicion}
Ejemplos:
Python
# 1. Obtener los cuadrados únicos de una lista con duplicados
numeros_con_duplicados = [1, 2, 2, 3, 4, 4, 5]
cuadrados_unicos = {num**2 for num in numeros_con_duplicados}
print(f"Cuadrados únicos: {cuadrados_unicos}")
# 2. Obtener las iniciales únicas de una lista de nombres
nombres = ["Ana", "Alicia", "Pedro", "Pablo", "Alberto"]
iniciales_unicas = {nombre[0] for nombre in nombres}
print(f"Iniciales únicas: {iniciales_unicas}")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
80 de 115
Manual completo de Python para Principiantes
A.3. Decoradores (@)
Los decoradores son una característica avanzada y muy elegante de Python que permite
modificar o extender el comportamiento de funciones o métodos sin cambiar su
código fuente directamente. Son esencialmente funciones que toman otra función como
argumento y devuelven una nueva función (generalmente una "función envuelta" que
añade funcionalidad).
La sintaxis del decorador usa el símbolo @ antes de la definición de una función.
¿Cuándo usarlos?
Logging: Registrar la entrada y salida de funciones.
Autenticación/Autorización: Verificar permisos antes de ejecutar una función.
Medición de rendimiento: Calcular cuánto tiempo tarda una función en ejecutarse.
Caché: Guardar resultados de funciones para no recalcularlos si se llaman con los
mismos argumentos.
Validación de entrada: Asegurarse de que los argumentos cumplen ciertas
condiciones.
Concepto Básico:
Un decorador es una función que:
1. Recibe una función como argumento.
2. Define una función interna (wrapper).
3. La función interna ejecuta código antes y/o después de llamar a la función original.
4. Devuelve la función interna.
Python
# Un ejemplo sencillo de un decorador para imprimir un mensaje antes y después de una función
def mi_primer_decorador(funcion_original):
def funcion_envoltura(*args, **kwargs): # *args y **kwargs permiten que la función envuelta acepte cualquier
número de argumentos
print("--- Antes de ejecutar la función ---")
resultado = funcion_original(*args, **kwargs) # Llama a la función original
print("--- Después de ejecutar la función ---")
return resultado # Devuelve el resultado de la función original
return funcion_envoltura
@mi_primer_decorador # Esta es la sintaxis del decorador
def saludar(nombre):
print(f"Hola, {nombre}!")
return "Saludo completado"
@mi_primer_decorador
def sumar(a, b):
print(f"Calculando suma de {a} y {b}...")
return a + b
# Ahora, cuando llamas a saludar(), en realidad estás llamando a funcion_envoltura
# que primero imprime el mensaje, luego llama a la función saludar original,
# luego imprime otro mensaje, y finalmente devuelve el resultado de saludar.
print("\nLlamando a la función saludar:")
saludar("Elena")
print("\nLlamando a la función sumar:")
res_suma = sumar(10, 5)
print(f"Resultado de la suma: {res_suma}")
# ¿Qué pasó internamente?
# saludar = mi_primer_decorador(saludar) # Esto es lo que hace @mi_primer_decorador
# sumar = mi_primer_decorador(sumar)
# Esto es lo que hace @mi_primer_decorador
Vicente Simón Rando
(CC BY-NC-ND 4.0)
81 de 115
Manual completo de Python para Principiantes
Decorador con Parámetros (Más avanzado): Puedes crear decoradores que acepten
argumentos, lo que los hace aún más flexibles. Esto implica una función anidada
adicional.
Python
def repetir(num_veces):
def decorador_repetir(funcion_original):
def funcion_envoltura(*args, **kwargs):
for _ in range(num_veces):
resultado = funcion_original(*args, **kwargs)
return resultado # Solo devolvemos el resultado de la última ejecución
return funcion_envoltura
return decorador_repetir
@repetir(num_veces=3) # El decorador con su parámetro
def gritar(mensaje):
print(mensaje.upper() + "!!!")
@repetir(num_veces=2)
def tarea_simple():
print("Realizando tarea simple...")
print("\nLlamando a la función gritar (repetida 3 veces):")
gritar("hola mundo")
print("\nLlamando a la función tarea_simple (repetida 2 veces):")
tarea_simple()
A.4. Generadores e Iteradores
Estos conceptos están estrechamente relacionados y son cruciales para trabajar
eficientemente con grandes conjuntos de datos o secuencias infinitas, ya que
permiten generar valores "sobre la marcha" en lugar de almacenar toda la secuencia en
memoria.
A.4.1. Iteradores
Un iterador es un objeto que representa un flujo de datos. Permite recorrer elementos
uno por uno. Cualquier objeto sobre el que puedas usar un bucle for es un iterable, y
ese bucle funciona porque Python obtiene un iterador de ese objeto.
Los iteradores implementan dos métodos especiales:
o
o
__iter__(): Debe devolver el propio objeto iterador.
__next__(): Debe devolver el siguiente elemento de la secuencia. Si no hay más
elementos, debe levantar la excepción StopIteration.
Python
# Ejemplo de un iterador personalizado (para entender el concepto)
class Contador:
def __init__(self, maximo):
self.maximo = maximo
self.actual = 0
def __iter__(self):
return self # El iterador es el propio objeto
def __next__(self):
if self.actual < self.maximo:
valor = self.actual
self.actual += 1
return valor
else:
raise StopIteration # Señal de que no hay más elementos
# Usando el iterador
mi_contador = Contador(5)
Vicente Simón Rando
(CC BY-NC-ND 4.0)
82 de 115
Manual completo de Python para Principiantes
for numero in mi_contador:
print(numero) # Salida: 0, 1, 2, 3, 4
# También puedes usar next() directamente
otro_contador = Contador(3)
print(next(otro_contador)) # Salida: 0
print(next(otro_contador)) # Salida: 1
print(next(otro_contador)) # Salida: 2
# print(next(otro_contador)) # Esto lanzaría StopIteration
A.4.2. Generadores
Un generador es una forma sencilla y concisa de crear iteradores. Una función se
convierte en un generador si usa la palabra clave yield en lugar de return.
Cuando una función generadora es llamada, no ejecuta todo el código inmediatamente.
En su lugar, devuelve un objeto generador (que es un tipo de iterador).
Cada vez que se llama a next() en el objeto generador (implícitamente por un bucle
for o explícitamente), la ejecución de la función generadora se reanuda desde donde se
quedó, hasta que encuentra la siguiente sentencia yield.
El valor de la expresión después de yield es el valor devuelto por next().
Cuando la función generadora finaliza (o encuentra un return sin valor), se levanta
automáticamente un StopIteration.
Ventajas:
Eficiencia de memoria: Generan valores "sobre la marcha", sin almacenar toda la
secuencia en memoria. Esto es crucial para datos muy grandes.
Código más limpio: A menudo, son más legibles que implementar la clase iteradora
completa.
Python
# Función generadora para generar números pares
def generador_pares(limite):
n = 0
while n <= limite:
yield n # 'yield' convierte esta función en un generador
n += 2
# Uso del generador
for par in generador_pares(10):
print(f"Par: {par}") # Salida: Par: 0, Par: 2, ..., Par: 10
# Puedes usar next() con un generador
gen = generador_pares(4)
print(next(gen)) # Salida: 0
print(next(gen)) # Salida: 2
print(next(gen)) # Salida: 4
# print(next(gen)) # Lanzaría StopIteration
# Ejemplo de uso práctico: leer un archivo muy grande línea por línea sin cargarlo completo
def leer_lineas_grandes(ruta_archivo):
with open(ruta_archivo, 'r') as f:
for linea in f:
yield linea.strip() # Genera una línea a la vez
# Simular un archivo grande (crear uno temporalmente)
with open("archivo_grande.txt", "w") as f:
for i in range(100000):
f.write(f"Esta es la línea número {i+1}\n")
print("\nLeyendo archivo grande con generador (observa que no se carga todo en memoria):")
lineas_procesadas = 0
for linea in leer_lineas_grandes("archivo_grande.txt"):
# print(linea) # No imprimir todas para no llenar la consola
lineas_procesadas += 1
if lineas_procesadas > 5: # Solo procesar las primeras 5 para ejemplo
break
print(f"Se procesaron {lineas_procesadas} líneas del archivo grande.")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
83 de 115
Manual completo de Python para Principiantes
A.5. Manejo Básico de Ficheros CSV (csv módulo)
Además de JSON, el formato CSV (Comma Separated Values) es extremadamente
común para almacenar datos tabulares (como hojas de cálculo). Cada línea es un
registro de datos, y los valores dentro de una línea están separados por un delimitador
(comúnmente una coma, pero puede ser punto y coma, tabulador, etc.).
El módulo estándar de Python csv facilita la lectura y escritura de estos archivos.
A.5.1. Lectura de Archivos CSV
csv.reader: Crea un objeto lector que itera sobre las líneas del archivo CSV. Cada fila
se devuelve como una lista de cadenas.
Python
import csv
# Contenido de un archivo 'datos.csv' (créalo o simúlalo)
# nombre,edad,ciudad
# Ana,28,Madrid
# Juan,34,Barcelona
# María,29,Sevilla
# Lectura básica
try:
with open('datos.csv', mode='r', encoding='utf-8') as archivo_csv:
lector_csv = csv.reader(archivo_csv)
# Saltar la cabecera si la hay (opcional)
cabecera = next(lector_csv)
print(f"Cabecera: {cabecera}")
for fila in lector_csv:
print(f"Fila: {fila}") # Cada fila es una lista de strings
except FileNotFoundError:
print("Error: El archivo 'datos.csv' no fue encontrado.")
except Exception as e:
print(f"Ocurrió un error al leer el CSV: {e}")
# Lectura como diccionario (csv.DictReader) - ¡Muy útil!
# Cada fila se devuelve como un diccionario con los nombres de las cabeceras como claves.
try:
with open('datos.csv', mode='r', encoding='utf-8') as archivo_csv:
lector_dict = csv.DictReader(archivo_csv)
for fila_dict in lector_dict:
print(f"Fila (Dict): Nombre: {fila_dict['nombre']}, Edad: {fila_dict['edad']}, Ciudad:
{fila_dict['ciudad']}")
# Puedes acceder a los campos por su nombre de cabecera
except FileNotFoundError:
print("Error: El archivo 'datos.csv' no fue encontrado.")
except Exception as e:
print(f"Ocurrió un error al leer el CSV con DictReader: {e}")
A.5.2. Escritura de Archivos CSV
csv.writer: Crea un objeto escritor que te permite escribir filas.
writer.writerow(lista): Escribe una sola fila.
writer.writerows(lista_de_listas): Escribe múltiples filas.
Python
import csv
datos_a_escribir = [
['producto', 'cantidad', 'precio'], # Cabecera
['Laptop', 10, 1200],
['Ratón', 50, 25],
['Teclado', 30, 75]
]
# Escritura básica
try:
with open('inventario.csv', mode='w', newline='', encoding='utf-8') as archivo_csv:
# newline='' es CRÍTICO para evitar que Python añada líneas en blanco extra
escritor_csv = csv.writer(archivo_csv)
escritor_csv.writerows(datos_a_escribir)
print("Archivo 'inventario.csv' creado/escrito correctamente.")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
84 de 115
Manual completo de Python para Principiantes
except IOError as e:
print(f"Error al escribir en el archivo CSV: {e}")
# Escritura como diccionario (csv.DictWriter) - requiere especificar los fieldnames (nombres de las columnas)
try:
datos_dict_a_escribir = [
{'nombre': 'Monitor', 'cantidad': 15, 'precio': 300},
{'nombre': 'Cámara', 'cantidad': 25, 'precio': 150}
]
# Debes especificar el orden de las columnas (fieldnames)
fieldnames = ['nombre', 'cantidad', 'precio']
with open('inventario_dict.csv', mode='w', newline='', encoding='utf-8') as archivo_csv:
escritor_dict = csv.DictWriter(archivo_csv, fieldnames=fieldnames)
escritor_dict.writeheader() # Escribe la primera fila con los fieldnames
escritor_dict.writerows(datos_dict_a_escribir)
print("Archivo 'inventario_dict.csv' creado/escrito correctamente.")
except IOError as e:
print(f"Error al escribir en el archivo CSV con DictWriter: {e}")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
85 de 115
Manual completo de Python para Principiantes
B. Propuestas de Ejercicios Adicionales
(Con su Solución Breve)
B.1. Ejercicios de Consolidación (Conceptos ya vistos)
Ejercicio B.1.1: Validador de Contraseñas
o
Descripción: Crea una función validar_contrasena(contrasena) que verifique si
una contraseña cumple con los siguientes criterios:
Longitud mínima de 8 caracteres.
o
Debe contener al menos una letra mayúscula.
o
Debe contener al menos una letra minúscula.
o
Debe contener al menos un dígito.
o
Debe contener al menos un carácter especial (ej. !@#$%^&*()-_+=).
La función debe devolver True si es válida y False en caso contrario. Imprime
mensajes explicativos para cada criterio que no se cumpla.
Pista: Usa el módulo re (expresiones regulares) para los patrones de caracteres.
Solución (Idea):
Python
import re
def validar_contrasena(contrasena):
if len(contrasena) < 8: return False # Comprobar longitud
if not re.search(r"[A-Z]", contrasena): return False # Mayúscula
if not re.search(r"[a-z]", contrasena): return False # Minúscula
if not re.search(r"\d", contrasena): return False # Dígito
if not re.search(r"[!@#$%^&*()-_+=]", contrasena): return False # Carácter especial
return True
Ejercicio B.1.2: Procesador de Archivo de Log
Descripción: Tienes un archivo log.txt con líneas como:
Vicente Simón Rando
(CC BY-NC-ND 4.0)
86 de 115
Manual completo de Python para Principiantes
[2024-07-18 10:35:12] ERROR: Archivo no encontrado
[2024-07-18 10:36:01] INFO: Inicio de sesión exitoso para usuario 'admin'
[2024-07-18 10:37:45] WARNING: Espacio en disco bajo (10% libre)
o
Crea una función analizar_log(ruta_archivo) que:
Lea el archivo línea por línea.
o
Extraiga la fecha/hora, el nivel (ERROR, INFO, WARNING) y el mensaje de cada
línea.
o
Almacene esta información en una lista de diccionarios.
o
Imprima un resumen: número total de líneas, número de ERRORES, INFOS y
WARNINGS.
Pista: Usa re.search o re.findall para extraer los patrones de cada línea y
datetime.strptime para las fechas.
Solución (Idea):
Python
import re, datetime
def analizar_log(ruta_archivo):
registros = []
patron_log = r"\[(.*?)\] (ERROR|INFO|WARNING): (.*)"
errores, infos, warnings = 0, 0, 0
with open(ruta_archivo, 'r') as f:
for linea in f:
match = re.search(patron_log, linea)
if match:
fecha_str, nivel, mensaje = match.groups()
registros.append({
"fecha": datetime.datetime.strptime(fecha_str, "%Y-%m-%d %H:%M:%S"),
"nivel": nivel,
"mensaje": mensaje
})
if nivel == "ERROR": errores += 1
elif nivel == "INFO": infos += 1
elif nivel == "WARNING": warnings += 1
print(f"Total de líneas: {len(registros)}")
print(f"Errores: {errores}, Infos: {infos}, Warnings: {warnings}")
return registros
Ejercicio B.1.3: Convertidor de Unidades con Diccionarios
Descripción: Crea una función convertir_unidad(valor, unidad_origen,
unidad_destino, tasas_conversion) que reciba un valor numérico, las unidades de
origen y destino, y un diccionario de tasas_conversion.
El diccionario de tasas podría ser algo como:
tasas = {"metros_a_pies": 3.28084, "libras_a_kg": 0.453592, "celsius_a_fahrenheit": (lambda c: (c * 9/5) + 32)}
La función debe buscar la tasa adecuada en el diccionario y realizar la conversión. Si la
tasa es una función (como en Celsius a Fahrenheit), debe ejecutarla.
Maneja KeyError si las unidades no se encuentran y TypeError si la tasa no es
aplicable.
Solución (Idea):
Python
def convertir_unidad(valor, u_origen, u_destino, tasas_conversion):
clave = f"{u_origen}_a_{u_destino}"
try:
tasa = tasas_conversion[clave]
if callable(tasa): # Si la tasa es una función (como lambda)
return tasa(valor)
else:
return valor * tasa
except KeyError:
return "Error: Tasa de conversión no encontrada."
except TypeError:
Vicente Simón Rando
(CC BY-NC-ND 4.0)
87 de 115
Manual completo de Python para Principiantes
return "Error: La tasa de conversión no es aplicable a este valor."
B.2. Ejercicios Introductorios a POO (Conceptos Nuevos)
Ejercicio B.2.1: Clase Libro
Descripción: Crea una clase Libro con los siguientes atributos: titulo, autor,
año_publicacion, esta_prestado (booleano, por defecto False).
Define los siguientes métodos:
o
__init__(self, titulo, autor, año_publicacion): Constructor para inicializar
los atributos.
o
prestar(self): Cambia esta_prestado a True si no lo está ya, e imprime un
mensaje.
o
o
devolver(self): Cambia esta_prestado a False si lo está ya, e imprime un mensaje.
__str__(self): Permite imprimir información legible del libro (ej. "Título: X, Autor:
Y (Año: Z)").1
Crea varios objetos Libro, pruébalos y muestra sus estados.2
Solución (Idea):
Python
class Libro:
def __init__(self, titulo, autor, año_publicacion):
self.titulo = titulo
self.autor = autor
self.año_publicacion = año_publicacion
self.esta_prestado = False
def prestar(self):
if not self.esta_prestado:
self.esta_prestado = True
print(f"'{self.titulo}' ha sido prestado.")
else:
print(f"'{self.titulo}' ya está prestado.")
def devolver(self):
if self.esta_prestado:
self.esta_prestado = False
print(f"'{self.titulo}' ha sido devuelto.")
else:
print(f"'{self.titulo}' no estaba prestado.")
def __str__(self):
estado = "Prestado" if self.esta_prestado else "Disponible"
return f"Título: {self.titulo}, Autor: {self.autor} (Año: {self.año_publicacion}) - Estado: {estado}"
Ejercicio B.2.2: Clase CuentaBancaria
Descripción: Crea una clase CuentaBancaria con atributos numero_cuenta, titular
y saldo (por defecto 0.0).
Define los siguientes métodos:
o
o
o
__init__(self, numero_cuenta, titular)
depositar(self, cantidad): Añade cantidad al saldo si es positiva.
retirar(self, cantidad): Resta cantidad del saldo si es positiva y hay suficiente
saldo.
o
o
consultar_saldo(self): Imprime el saldo actual.
Maneja casos de cantidades inválidas (no positivas) y saldo insuficiente con mensajes
adecuados.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
88 de 115
Manual completo de Python para Principiantes
Solución (Idea):
Python
class CuentaBancaria:
def __init__(self, numero_cuenta, titular):
self.numero_cuenta = numero_cuenta
self.titular = titular
self.saldo = 0.0
def depositar(self, cantidad):
if cantidad > 0:
self.saldo += cantidad
print(f"Depósito de {cantidad:.2f}€. Nuevo saldo: {self.saldo:.2f}€")
else:
print("La cantidad a depositar debe ser positiva.")
def retirar(self, cantidad):
if cantidad <= 0:
print("La cantidad a retirar debe ser positiva.")
elif cantidad > self.saldo:
print("Saldo insuficiente.")
else:
self.saldo -= cantidad
print(f"Retiro de {cantidad:.2f}€. Nuevo saldo: {self.saldo:.2f}€")
def consultar_saldo(self):
print(f"Saldo actual de la cuenta {self.numero_cuenta}: {self.saldo:.2f}€")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
89 de 115
Manual completo de Python para Principiantes
C. Manejo de Logs: Registrando Eventos
de tu Aplicación
Los logs (registros) son mensajes que tu programa escribe para documentar los eventos
que ocurren durante su ejecución. Son cruciales para la depuración, el monitoreo del
rendimiento y la auditoría de lo que hace tu aplicación. Python proporciona el módulo
logging para manejar esto de manera eficiente y flexible.
C.1. ¿Por qué usar Logs?
Depuración: Ayudan a encontrar y corregir errores, mostrando el flujo de ejecución y
los valores de las variables.
Monitoreo: Permiten supervisar la salud y el rendimiento de tu aplicación en
producción.
Auditoría: Registran eventos importantes, como inicios de sesión, transacciones, o
errores críticos, para seguimiento y cumplimiento.
Análisis: Los datos de los logs pueden ser analizados para identificar patrones, cuellos
de botella o comportamientos inesperados.
C.2. Niveles de Logging
Vicente Simón Rando
(CC BY-NC-ND 4.0)
90 de 115
Manual completo de Python para Principiantes
El módulo logging define varios niveles de severidad para los mensajes, lo que te
permite filtrar qué mensajes se muestran o se guardan. Ordenados de menor a mayor
severidad:
DEBUG: Información detallada, típicamente de interés solo al diagnosticar problemas.
INFO: Confirmación de que las cosas están funcionando como se esperaba.
WARNING: Una indicación de que algo inesperado ha sucedido, o un indicio de algún
problema en el futuro cercano (ej. 'espacio en disco bajo'). El software sigue
funcionando como se esperaba.
ERROR: Debido a un problema más serio, el software no ha podido realizar alguna
función.
CRITICAL: Un error grave, indicando que el programa en sí no puede continuar
ejecutándose.
Por defecto, el nivel de registro es WARNING, lo que significa que solo los mensajes
WARNING, ERROR y CRITICAL se mostrarán en la consola si no configuras nada más.
C.3. Configuración Básica de Logs
La forma más sencilla de empezar es usando las funciones del módulo directamente.
Python
import logging
# Configuración básica (antes de cualquier llamada a logging)
# Esto sobrescribe la configuración por defecto
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logging.debug("Este es un mensaje de depuración.")
# No se mostrará con INFO
logging.info("Este es un mensaje informativo.")
# Se mostrará
logging.warning("Este es un mensaje de advertencia.") # Se mostrará
logging.error("Este es un mensaje de error.")
# Se mostrará
logging.critical("Este es un mensaje crítico.")
# Se mostrará
Explicación de basicConfig parámetros comunes:
o
o
o
o
o
o
level: Establece el umbral de los mensajes que se procesarán.
format: Define el formato del mensaje del log. Algunos formatos útiles:
%(asctime)s: Tiempo de registro (ej. 2023-10-27 10:30:45,123).
%(levelname)s: Nivel de severidad del mensaje (DEBUG, INFO, WARNING, etc.).
%(message)s: El mensaje real que quieres registrar.
%(name)s: Nombre del logger que emitió el evento (útil en aplicaciones grandes).
%(filename)s: Nombre del archivo fuente donde ocurrió el log.
%(lineno)d: Número de línea donde ocurrió el log.
filename: Especifica un archivo donde se escribirán los logs en lugar de la consola.
filemode: Modo de apertura del archivo ('w' para sobrescribir, 'a' para añadir, por
defecto es 'a').
Ejemplo de Logging a un Archivo:
Python
import logging
Vicente Simón Rando
(CC BY-NC-ND 4.0)
91 de 115
Manual completo de Python para Principiantes
# Configurar para escribir logs en un archivo
logging.basicConfig(
level=logging.DEBUG, # Aquí ponemos DEBUG para ver todos los mensajes en el archivo
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
filename='mi_aplicacion.log', # Nombre del archivo de log
filemode='w' # 'w' para que se cree un nuevo archivo cada vez que se ejecute
)
# Mensajes de log
logging.debug("Iniciando la aplicación...")
logging.info("Procesando datos del usuario.")
try:
resultado = 10 / 0
except ZeroDivisionError:
logging.error("Error: Intento de división por cero.", exc_info=True) # exc_info=True incluye la traza de la
excepción
logging.warning("Operación completada con algunas advertencias.")
Después de ejecutar este código, verás un archivo llamado mi_aplicacion.log en la
misma carpeta con los mensajes registrados.
C.4. Uso de Loggers Personalizados
Para aplicaciones más complejas, es mejor crear tus propios objetos logger en lugar de
usar las funciones globales del módulo logging. Esto te da más control y te permite
configurar diferentes loggers para diferentes partes de tu aplicación.
Python
import logging
# 1. Obtener un objeto logger
# El nombre es opcional, pero ayuda a identificar de dónde vienen los logs
app_logger = logging.getLogger('mi_app_principal')
app_logger.setLevel(logging.DEBUG) # Establece el nivel para este logger
# 2. Crear un "handler" (manejador) para dónde irán los logs
# Console Handler: Para imprimir en la consola
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO) # Los logs de nivel INFO o superior van a la consola
# File Handler: Para escribir en un archivo
file_handler = logging.FileHandler('app_debug.log', mode='a') # 'a' para añadir
file_handler.setLevel(logging.DEBUG) # Todos los logs DEBUG o superior van al archivo
# 3. Definir un formato para los handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# Asignar el formato a los handlers
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
# 4. Añadir los handlers al logger
app_logger.addHandler(console_handler)
app_logger.addHandler(file_handler)
# Ahora usa el logger personalizado
app_logger.debug("Mensaje de depuración del logger de la app.")
app_logger.info("Mensaje informativo del logger de la app.")
app_logger.warning("Mensaje de advertencia del logger de la app.")
app_logger.error("Mensaje de error del logger de la app.")
# Ejemplo de un logger para un módulo específico
mod_logger = logging.getLogger('mi_app_principal.modulo_calculo') # Es una jerarquía
mod_logger.debug("Calculando valores críticos en el módulo de cálculo.")
Resumen del flujo:
Logger: El objeto principal que recibes o creas. Define el nivel mínimo para procesar
un mensaje.
Handler: Determina a dónde van los mensajes (consola, archivo, red, etc.) y también
tiene su propio nivel.
Formatter: Define cómo se verá el mensaje final.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
92 de 115
Manual completo de Python para Principiantes
Esta flexibilidad te permite, por ejemplo, enviar mensajes DEBUG a un archivo para
depuración profunda, mientras que solo los INFO y superiores se muestran en la consola
para un monitoreo general.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
93 de 115
Manual completo de Python para Principiantes
D. Batería de Ejercicios de Python
Sección 1: Fundamentos (Variables, Operadores,
Condicionales, Bucles)
1. Saludo Personalizado
Propuesta: Pide al usuario su nombre y salúdalo con un mensaje.
Solución:
Python
nombre = input("¿Cuál es tu nombre? ")
print(f"¡Hola, {nombre}! Bienvenido a Python.")
2. Suma de Dos Números
Propuesta: Pide al usuario dos números enteros y muestra su suma.
Solución:
Python
num1 = int(input("Introduce el primer número: "))
num2 = int(input("Introduce el segundo número: "))
suma = num1 + num2
print(f"La suma es: {suma}")
3. Número Par o Impar
Propuesta: Pide un número y di si es par o impar.
Solución:
Python
num = int(input("Introduce un número: "))
if num % 2 == 0:
print("El número es par.")
else:
print("El número es impar.")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
94 de 115
Manual completo de Python para Principiantes
4. Mayor de Tres Números
Propuesta: Pide tres números y muestra el mayor de ellos.
Solución:
Python
a = int(input("Número 1: "))
b = int(input("Número 2: "))
c = int(input("Número 3: "))
print(f"El mayor es: {max(a, b, c)}")
5. Contar hasta 5
Propuesta: Imprime los números del 1 al 5 usando un bucle for.
Solución:
Python
for i in range(1, 6):
print(i)
6. Cuenta Regresiva
Propuesta: Imprime una cuenta regresiva desde 5 hasta 1 usando un bucle while.
Solución:
Python
contador = 5
while contador >= 1:
print(contador)
contador -= 1
7. Tabla de Multiplicar del 7
Propuesta: Imprime la tabla de multiplicar del 7 (del 7x1 al 7x10).
Solución:
Python
for i in range(1, 11):
print(f"7 x {i} = {7 * i}")
8. Suma Acumulada
Propuesta: Pide números al usuario hasta que introduzca 0. Muestra la suma total.
Solución:
Python
suma_total = 0
while True:
num = int(input("Introduce un número (0 para terminar): "))
if num == 0:
break
suma_total += num
print(f"La suma total es: {suma_total}")
9. Adivina el Número
Vicente Simón Rando
(CC BY-NC-ND 4.0)
95 de 115
Manual completo de Python para Principiantes
Propuesta: Genera un número aleatorio entre 1 y 10. Pide al usuario que lo adivine,
dándole pistas si es mayor o menor.
Solución:
Python
import random
numero_secreto = random.randint(1, 10)
intentos = 0
while True:
intento = int(input("Adivina el número (entre 1 y 10): "))
intentos += 1
if intento == numero_secreto:
print(f"¡Felicidades! Adivinaste el número en {intentos} intentos.")
break
elif intento < numero_secreto:
print("El número es mayor. Intenta de nuevo.")
else:
print("El número es menor. Intenta de nuevo.")
10. Patrón de Asteriscos
Propuesta: Imprime un patrón de asteriscos como este:
*
**
***
****
*****
Solución:
Python
for i in range(1, 6):
print("*" * i)
Sección 2: Estructuras de Datos (Listas, Tuplas,
Diccionarios, Conjuntos)
11. Acceder Elemento de Lista
Propuesta: Dada una lista frutas = ["manzana", "banana", "cereza"], imprime
el segundo elemento.
Solución:
Python
frutas = ["manzana", "banana", "cereza"]
print(frutas[1])
12. Añadir a Lista
Propuesta: A la lista del ejercicio anterior, añade "naranja" al final.
Solución:
Python
frutas = ["manzana", "banana", "cereza"]
Vicente Simón Rando
(CC BY-NC-ND 4.0)
96 de 115
Manual completo de Python para Principiantes
frutas.append("naranja")
print(frutas)
13. Eliminar de Lista
Propuesta: De la lista resultante, elimina "banana".
Solución:
Python
frutas = ["manzana", "banana", "cereza", "naranja"]
frutas.remove("banana")
print(frutas)
14. Longitud de Lista
Propuesta: Imprime cuántos elementos tiene la lista actual de frutas.
Solución:
Python
frutas = ["manzana", "cereza", "naranja"]
print(len(frutas))
15. Iterar Lista
Propuesta: Itera sobre la lista colores = ["rojo", "verde", "azul"] e imprime
cada color.
Solución:
Python
colores = ["rojo", "verde", "azul"]
for color in colores:
print(color)
16. Modificar Elemento de Tupla (Error Común)
Propuesta: Intenta modificar el primer elemento de la tupla coordenadas = (10,
20). ¿Qué ocurre?
Solución:
Python
coordenadas = (10, 20)
# coordenadas[0] = 15 # Esto causará un TypeError, las tuplas son inmutables
print("Las tuplas son inmutables, no se pueden modificar sus elementos directamente.")
17. Acceder Valor de Diccionario
Propuesta: Dado el diccionario persona = {"nombre": "Juan", "edad": 30},
imprime el valor de "nombre".
Solución:
Python
persona = {"nombre": "Juan", "edad": 30}
print(persona["nombre"])
18. Añadir a Diccionario
Vicente Simón Rando
(CC BY-NC-ND 4.0)
97 de 115
Manual completo de Python para Principiantes
Propuesta: Al diccionario persona, añade la clave "ciudad" con valor "Madrid".
Solución:
Python
persona = {"nombre": "Juan", "edad": 30}
persona["ciudad"] = "Madrid"
print(persona)
19. Iterar Claves y Valores de Diccionario
Propuesta: Itera sobre el diccionario temperaturas = {"Lunes": 25, "Martes":
28, "Miércoles": 22} e imprime cada día y su temperatura.
Solución:
Python
temperaturas = {"Lunes": 25, "Martes": 28, "Miércoles": 22}
for dia, temp in temperaturas.items():
print(f"{dia}: {temp}°C")
20. Operaciones con Conjuntos
Propuesta: Dados conjunto1 = {1, 2, 3, 4} y conjunto2 = {3, 4, 5, 6},
imprime su unión, intersección y diferencia (elementos en conjunto1 pero no en
conjunto2).
Solución:
Python
conjunto1 = {1, 2, 3, 4}
conjunto2 = {3, 4, 5, 6}
print(f"Unión: {conjunto1.union(conjunto2)}")
print(f"Intersección: {conjunto1.intersection(conjunto2)}")
print(f"Diferencia (c1 - c2): {conjunto1.difference(conjunto2)}")
Sección 3: Funciones y Alcance
21. Función saludar
Propuesta: Crea una función saludar(nombre) que imprima "Hola, [nombre]!".
Solución:
Python
def saludar(nombre):
print(f"Hola, {nombre}!")
saludar("Marta")
22. Función sumar_dos
Propuesta: Crea una función sumar_dos(a, b) que retorne la suma de a y b.
Solución:
Python
def sumar_dos(a, b):
Vicente Simón Rando
(CC BY-NC-ND 4.0)
98 de 115
Manual completo de Python para Principiantes
return a + b
resultado = sumar_dos(8, 5)
print(f"Resultado de la suma: {resultado}")
23. Función con Valor por Defecto
Propuesta: Modifica la función saludar para que si no se proporciona nombre, salude
a "Invitado".
Solución:
Python
def saludar(nombre="Invitado"):
print(f"Hola, {nombre}!")
saludar()
saludar("Luis")
24. Alcance de Variable (Local vs Global)
Propuesta: Explica qué imprimirán estas líneas y por qué.
Python
x = 10
def mi_funcion():
x = 5
print(f"Dentro de la función: {x}")
mi_funcion()
print(f"Fuera de la función: {x}")
Solución:
Python
x = 10
def mi_funcion():
x = 5 # Esta 'x' es local a mi_funcion
print(f"Dentro de la función: {x}") # Imprime 5
mi_funcion()
print(f"Fuera de la función: {x}") # Imprime 10 (la 'x' global no fue afectada)
# Razón: Las variables dentro de una función tienen alcance local, a menos que se use 'global'.
25. Función Lambda (Anónima)
Propuesta: Crea una función lambda que multiplique un número por 3 y úsala con el
número 4.
Solución:
Python
multiplicar_por_3 = lambda x: x * 3
print(multiplicar_por_3(4))
Sección 4: Manejo de Errores y Excepciones
26. División Segura
Propuesta: Pide dos números. Realiza la división, pero maneja ZeroDivisionError si
el segundo número es 0 y ValueError si no son números.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
99 de 115
Manual completo de Python para Principiantes
Solución:
Python
try:
num1 = float(input("Numerador: "))
num2 = float(input("Denominador: "))
resultado = num1 / num2
print(f"Resultado: {resultado}")
except ZeroDivisionError:
print("Error: No se puede dividir por cero.")
except ValueError:
print("Error: Por favor, introduce solo números.")
27. Acceso a Índice Seguro
Propuesta: Dada una lista nombres = ["Ana", "Bea"], pide al usuario un índice y
muestra el nombre. Maneja IndexError.
Solución:
Python
nombres = ["Ana", "Bea"]
try:
indice = int(input("Introduce un índice (0 o 1): "))
print(f"Nombre: {nombres[indice]}")
except IndexError:
print("Error: Índice fuera de rango.")
except ValueError:
print("Error: Por favor, introduce un número entero.")
28. Bloque finally
Propuesta: Escribe un try-except-finally que intente una operación (que pueda
fallar o no) y el bloque finally siempre imprima "Operación finalizada".
Solución:
Python
try:
# Puede fallar: 10 / 0
# Puede no fallar: print("Todo bien")
print(10 / 2)
except ZeroDivisionError:
print("¡Error de división!")
finally:
print("Operación finalizada.")
Sección 5: Módulos y Paquetes
29. Usar math.pi
Propuesta: Importa el módulo math e imprime el valor de PI.
Solución:
Python
import math
print(f"El valor de PI es: {math.pi}")
30. Número Aleatorio con random
Vicente Simón Rando
(CC BY-NC-ND 4.0)
100 de 115
Manual completo de Python para Principiantes
Propuesta: Importa el módulo random y genera un número entero aleatorio entre 1 y
100.
Solución:
Python
import random
num_aleatorio = random.randint(1, 100)
print(f"Número aleatorio: {num_aleatorio}")
31. Alias de Módulo
Propuesta: Importa math como m e imprime la raíz cuadrada de 16.
Solución:
Python
import math as m
print(f"Raíz cuadrada de 16: {m.sqrt(16)}")
32. Importar Específico
Propuesta: Importa solo la función sin del módulo math y calcula el seno de 0.
Solución:
Python
from math import sin
print(f"Seno de 0: {sin(0)}")
Sección 6: Trabajando con Datos Externos (Ficheros, JSON,
Datetime)
33. Escribir en un Archivo
Propuesta: Escribe las líneas "Línea 1\n" y "Línea 2\n" en un archivo llamado
ejemplo.txt.
Solución:
Python
with open("ejemplo.txt", "w") as f:
f.write("Línea 1\n")
f.write("Línea 2\n")
print("Archivo 'ejemplo.txt' escrito.")
34. Leer de un Archivo
Propuesta: Lee y muestra todo el contenido del archivo ejemplo.txt creado
anteriormente.
Solución:
Python
with open("ejemplo.txt", "r") as f:
Vicente Simón Rando
(CC BY-NC-ND 4.0)
101 de 115
Manual completo de Python para Principiantes
contenido = f.read()
print("Contenido de 'ejemplo.txt':")
print(contenido)
35. Añadir a un Archivo
Propuesta: Añade "Nueva línea\n" al final de ejemplo.txt.
Solución:
Python
with open("ejemplo.txt", "a") as f:
f.write("Nueva línea\n")
print("Nueva línea añadida a 'ejemplo.txt'.")
36. Leer Línea a Línea
Propuesta: Lee y muestra cada línea de ejemplo.txt una por una.
Solución:
Python
with open("ejemplo.txt", "r") as f:
for linea in f:
print(f"Leído: {linea.strip()}")
37. Guardar Diccionario como JSON
Propuesta: Guarda un diccionario {"nombre": "Alice", "edad": 25} en un archivo
datos.json.
Solución:
Python
import json
datos = {"nombre": "Alice", "edad": 25}
with open("datos.json", "w") as f:
json.dump(datos, f, indent=4)
print("Diccionario guardado en 'datos.json'.")
38. Cargar JSON a Diccionario
Propuesta: Carga el contenido de datos.json y muéstralo.
Solución:
Python
import json
with open("datos.json", "r") as f:
datos_cargados = json.load(f)
print("Datos cargados de 'datos.json':")
print(datos_cargados)
39. Fecha y Hora Actual
Propuesta: Imprime la fecha y hora actual usando datetime.
Solución:
Python
import datetime
ahora = datetime.datetime.now()
print(f"Fecha y hora actual: {ahora}")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
102 de 115
Manual completo de Python para Principiantes
40. Formatear Fecha
Propuesta: Formatea la fecha y hora actual para que se muestre como "DD-MMAAAA HH:MM".
Solución:
Python
import datetime
ahora = datetime.datetime.now()
formato = ahora.strftime("%d-%m-%Y %H:%M")
print(f"Fecha formateada: {formato}")
Sección 7: Librerías Útiles (Requests, Re, Pandas)
41. Petición GET Simple con requests
Propuesta: Haz una petición GET a https://api.github.com/events e imprime el
código de estado de la respuesta.
Solución:
Python
import requests
try:
respuesta = requests.get("https://api.github.com/events")
print(f"Código de estado: {respuesta.status_code}")
except requests.exceptions.RequestException as e:
print(f"Error en la petición: {e}")
42. Extraer Emails con re
Propuesta: Dada la cadena "Contacto: info@empresa.com o
soporte@servicio.org", extrae todos los emails usando re.findall.
Solución:
Python
import re
texto = "Contacto: info@empresa.com o soporte@servicio.org"
emails = re.findall(r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b", texto)
print(f"Emails encontrados: {emails}")
43. Crear DataFrame Simple con pandas
Propuesta: Crea un DataFrame de pandas con dos columnas: Nombre (con "Ana",
"Luis") y Edad (con 25, 30).
Solución:
Python
import pandas as pd
data = {'Nombre': ['Ana', 'Luis'], 'Edad': [25, 30]}
df = pd.DataFrame(data)
print(df)
44. Filtrar DataFrame con pandas
Vicente Simón Rando
(CC BY-NC-ND 4.0)
103 de 115
Manual completo de Python para Principiantes
Propuesta: Del DataFrame anterior, filtra y muestra solo las personas cuya edad sea
mayor a 25.
Solución:
Python
import pandas as pd
data = {'Nombre': ['Ana', 'Luis'], 'Edad': [25, 30]}
df = pd.DataFrame(data)
df_filtrado = df[df['Edad'] > 25]
print(df_filtrado)
Sección 8: Conceptos Adicionales (POO, Comprehensions,
Generadores, CSV)
45. Clase Animal (POO)
Propuesta: Crea una clase Animal con un constructor que reciba nombre y especie.
Añade un método hacer_sonido() que imprima "El [especie] [nombre] hace un
sonido."
Solución:
Python
class Animal:
def __init__(self, nombre, especie):
self.nombre = nombre
self.especie = especie
def hacer_sonido(self):
print(f"El {self.especie} {self.nombre} hace un sonido.")
mi_perro = Animal("Max", "perro")
mi_perro.hacer_sonido()
46. Herencia con Clase Perro (POO)
Propuesta: Crea una clase Perro que herede de Animal. El constructor de Perro debe
recibir nombre, raza y llamar al constructor de Animal. Sobrescribe hacer_sonido()
para que diga "El perro [nombre] ladra.".
Solución:
Python
class Animal:
def __init__(self, nombre, especie):
self.nombre = nombre
self.especie = especie
def hacer_sonido(self):
print(f"El {self.especie} {self.nombre} hace un sonido.")
class Perro(Animal):
def __init__(self, nombre, raza):
super().__init__(nombre, "perro") # Llama al constructor de Animal
self.raza = raza
def hacer_sonido(self): # Sobrescribe el método
print(f"El perro {self.nombre} de raza {self.raza} ladra: ¡Guau! ¡Guau!")
mi_perro_especifico = Perro("Buddy", "Golden Retriever")
mi_perro_especifico.hacer_sonido()
47. Comprensión de Listas para Pares
Vicente Simón Rando
(CC BY-NC-ND 4.0)
104 de 115
Manual completo de Python para Principiantes
Propuesta: Crea una lista de los números pares del 0 al 20 usando una comprensión de
listas.
Solución:
Python
pares = [i for i in range(21) if i % 2 == 0]
print(f"Pares: {pares}")
48. Comprensión de Diccionarios (Precio con Impuestos)
Propuesta: Dado precios = {"manzana": 1.0, "banana": 0.5}, crea un nuevo
diccionario precios_con_impuestos donde cada precio tenga un impuesto del 21%
aplicado (precio * 1.21).
Solución:
Python
precios = {"manzana": 1.0, "banana": 0.5}
precios_con_impuestos = {fruta: precio * 1.21 for fruta, precio in precios.items()}
print(f"Precios con impuestos: {precios_con_impuestos}")
49. Generador de Fibonacci
Propuesta: Crea una función generadora fibonacci(n) que genere los primeros n
números de la secuencia de Fibonacci.
Solución:
Python
def fibonacci(n):
a, b = 0, 1
contador = 0
while contador < n:
yield a
a, b = b, a + b
contador += 1
print("Primeros 10 números de Fibonacci:")
for num in fibonacci(10):
print(num, end=" ") # 0 1 1 2 3 5 8 13 21 34
print()
50. Leer y Procesar CSV Simple
Propuesta: Dado un archivo productos.csv con (crea el archivo):
item,cantidad
camiseta,10
pantalon,5
gorra,12
Lee este CSV usando csv.DictReader y calcula la cantidad total de ítems.
Solución:
Python
# productos.csv (crear este archivo en la misma carpeta)
# item,cantidad
# camiseta,10
# pantalon,5
# gorra,12
import csv
total_cantidad = 0
Vicente Simón Rando
(CC BY-NC-ND 4.0)
105 de 115
Manual completo de Python para Principiantes
try:
with open('productos.csv', mode='r', encoding='utf-8') as archivo_csv:
lector_dict = csv.DictReader(archivo_csv)
for fila in lector_dict:
total_cantidad += int(fila['cantidad'])
print(f"Cantidad total de ítems: {total_cantidad}")
except FileNotFoundError:
print("Error: 'productos.csv' no encontrado.")
except Exception as e:
print(f"Error al procesar CSV: {e}")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
106 de 115
Manual completo de Python para Principiantes
E. Creando APIs Web con FastAPI y
Uvicorn
Ahora que dominas los fundamentos de Python, es hora de llevar tus habilidades al
siguiente nivel creando APIs web. Una API (Interfaz de Programación de Aplicaciones)
permite que diferentes sistemas se comuniquen entre sí. FastAPI es un framework de
Python moderno, rápido y fácil de usar para construir APIs. Uvicorn es el servidor
ASGI (Asynchronous Server Gateway Interface) que ejecuta las aplicaciones FastAPI.
E.1. ¿Qué es FastAPI y por qué usarlo?
FastAPI se ha vuelto increíblemente popular por varias razones:
Velocidad: Es uno de los frameworks de Python más rápidos, gracias a que está
construido sobre Starlette (para la web) y Pydantic (para la validación de datos).
Fácil de codificar: Requiere muy poco código para crear APIs robustas.
Documentación automática: Genera automáticamente documentación interactiva
(Swagger UI y ReDoc) para tu API, lo que facilita a otros desarrolladores entender y
usar tu servicio.
Validación de datos: Utiliza Pydantic para la validación de datos automática y la
serialización/deserialización, lo que reduce drásticamente los errores.
Soporte asíncrono: Permite manejar solicitudes concurrentes de manera eficiente.
Vicente Simón Rando
(CC BY-NC-ND 4.0)
107 de 115
Manual completo de Python para Principiantes
E.2. Instalación de FastAPI y Uvicorn
Primero, necesitas instalar las librerías. Abre tu terminal y ejecuta:
Bash
pip install fastapi uvicorn[standard]
fastapi: El framework web en sí.
uvicorn[standard]: El servidor que ejecutará tu aplicación FastAPI. La parte
[standard] instala extras comunes necesarios.
E.3. Tu Primera API: Petición GET Básica
Vamos a crear una API simple que responda a una petición GET en la ruta raíz (/).
1. Crea un archivo llamado main.py (o cualquier otro nombre que prefieras).
Python
# main.py
from fastapi import FastAPI
# Creamos una instancia de FastAPI
app = FastAPI()
# Definimos una ruta GET en la raíz (/)
@app.get("/")
async def read_root():
return {"mensaje": "¡Hola, mundo desde FastAPI!"}
2. Ejecuta la aplicación con Uvicorn. Abre tu terminal en el directorio donde guardaste
main.py y ejecuta:
Bash
uvicorn main:app --reload
o
o
o
main: Se refiere al archivo main.py.
app: Se refiere a la instancia app = FastAPI() dentro de main.py.
--reload: Es muy útil durante el desarrollo, ya que el servidor se reiniciará
automáticamente cada vez que guardes cambios en tu código.
3. Accede a tu API. Abre tu navegador y ve a http://127.0.0.1:8000. Deberías ver un
JSON con el mensaje: {"mensaje": "¡Hola, mundo desde FastAPI!"}.
Documentación automática: Visita http://127.0.0.1:8000/docs para ver la
documentación interactiva generada automáticamente por Swagger UI, o
http://127.0.0.1:8000/redoc para la versión de ReDoc. ¡Es una pasada!
E.4. Petición GET con Parámetros de Ruta y Query
Vicente Simón Rando
(CC BY-NC-ND 4.0)
108 de 115
Manual completo de Python para Principiantes
FastAPI hace que el manejo de parámetros sea muy sencillo.
Parámetros de Ruta: Son parte de la URL (ej. /items/5).
Parámetros de Query (Consulta): Vienen después del ? en la URL (ej.
/items?limit=10).
Python
# main.py (continúa añadiendo a tu archivo existente)
from fastapi import FastAPI
from typing import Optional # Para parámetros opcionales
app = FastAPI()
# ... (código anterior de read_root)
# Petición GET con un parámetro de ruta
@app.get("/items/{item_id}")
async def read_item(item_id: int): # FastAPI valida automáticamente que item_id sea un entero
return {"item_id": item_id, "descripcion": f"Este es el item número {item_id}"}
# Petición GET con parámetro de ruta y parámetro de query opcional
@app.get("/users/{user_id}")
async def read_user(user_id: int, q: Optional[str] = None):
# 'q: Optional[str] = None' significa que 'q' es un string que es opcional y por defecto es None
if q:
return {"user_id": user_id, "query": q, "message": f"Buscando usuario {user_id} con consulta '{q}'"}
return {"user_id": user_id, "message": f"Usuario {user_id} encontrado sin consulta"}
Para probarlo:
http://127.0.0.1:8000/items/123
http://127.0.0.1:8000/users/5
http://127.0.0.1:8000/users/5?q=activo
E.5. Petición POST: Enviando Datos al Servidor
Las peticiones POST se usan para enviar datos al servidor, típicamente para crear nuevos
recursos. FastAPI utiliza Pydantic para definir la estructura de los datos que esperas en
el cuerpo de la petición (el "payload").
1. Define un modelo de datos con Pydantic.
Python
# main.py (continúa añadiendo a tu archivo existente)
from fastapi import FastAPI
from typing import Optional
from pydantic import BaseModel # Importamos BaseModel de Pydantic
app = FastAPI()
# ... (código anterior)
# Definimos un modelo Pydantic para el Item
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None
# Petición POST para crear un nuevo item
@app.post("/items/")
async def create_item(item: Item): # FastAPI espera que el cuerpo de la petición sea un objeto Item
item_dict = item.model_dump() # Convertimos el objeto Item a un diccionario
if item.tax:
price_with_tax = item.price + item.tax
item_dict.update({"price_with_tax": price_with_tax})
return {"message": "Item creado con éxito", "item": item_dict}
Vicente Simón Rando
(CC BY-NC-ND 4.0)
109 de 115
Manual completo de Python para Principiantes
2. Para probar una petición POST:
o Swagger UI: La forma más fácil es ir a http://127.0.0.1:8000/docs, expandir el endpoint
/items/ (POST) y hacer clic en "Try it out". Podrás introducir un cuerpo de JSON de
ejemplo y ejecutar la petición.
o cURL (Terminal):
Bash
curl -X POST "http://127.0.0.1:8000/items/" \
-H "Content-Type: application/json" \
-d '{
"name": "Libro de Python",
"description": "Un gran libro para aprender Python.",
"price": 29.99,
"tax": 0.05
}'
o
Postman/Insomnia: Estas herramientas son excelentes para probar APIs. Configura
una petición POST a http://127.0.0.1:8000/items/, selecciona "Raw" y "JSON"
como tipo de cuerpo, y pega el JSON de ejemplo.
E.6. Estructura de la Respuesta JSON
Como has visto en los ejemplos, FastAPI automáticamente convierte los diccionarios o
modelos Pydantic que retornas de tus funciones a respuestas JSON válidas.
Si retornas un diccionario, FastAPI lo serializa a JSON.
Si retornas una instancia de un modelo Pydantic, FastAPI primero lo convierte a un
diccionario y luego a JSON.
FastAPI también maneja la serialización de tipos de datos complejos como datetime o
UUID si se especifican correctamente en los modelos de Pydantic.
Ejemplo de respuesta compleja:
Python
# main.py (continúa añadiendo a tu archivo existente)
from fastapi import FastAPI
from typing import Optional
from pydantic import BaseModel
import datetime
app = FastAPI()
# ... (código anterior)
class Order(BaseModel):
order_id: int
items: list[Item] # Una lista de objetos Item
customer_name: str
order_date: datetime.datetime # FastAPI sabe cómo serializar esto
total_amount: float
@app.post("/orders/")
async def create_order(order: Order):
# Aquí podrías guardar la orden en una base de datos, etc.
return {
"status": "success",
"message": f"Orden {order.order_id} recibida para {order.customer_name}",
"order_details": order.model_dump() # Convertir el objeto Order a diccionario para la respuesta
}
Para probarlo (ejemplo de JSON de entrada para /orders/ POST):
Vicente Simón Rando
(CC BY-NC-ND 4.0)
110 de 115
Manual completo de Python para Principiantes
JSON
{
"order_id": 1,
"items": [
{
"name": "Camiseta",
"price": 15.00
},
{
"name": "Pantalón",
"description": "Pantalón vaquero",
"price": 40.00,
"tax": 0.08
}
],
"customer_name": "Laura García",
"order_date": "2025-07-20T22:30:00.000Z",
"total_amount": 55.00
}
FastAPI automáticamente validará este JSON contra tu modelo Order y te dará errores
claros si el formato o los tipos de datos no coinciden. Esto es una de sus mayores
fortalezas.
Con FastAPI y Uvicorn, tienes una combinación potente para crear APIs web rápidas,
robustas y auto-documentadas con muy poco esfuerzo. ¡Es una herramienta esencial
para el desarrollo web moderno en Python!
E.7. Código Google Colab para crear el servidor
Colab
!pip install fastapi nest-asyncio pyngrok uvicorn
Colab
# Importar librerías necesarias
from fastapi import FastAPI
import uvicorn
from pyngrok import ngrok
import nest_asyncio
import os
from google.colab import userdata
from typing import Optional
from pydantic import BaseModel
import datetime
# Aplicar nest_asyncio para permitir la ejecución de bucles de eventos anidados,
# lo cual es necesario para Uvicorn en entornos como Colab.
nest_asyncio.apply()
# Crear una instancia de FastAPI
app = FastAPI()
# Definir una ruta GET en la raíz (/)
@app.get("/")
async def read_root():
"""
Define la ruta raíz que devuelve un mensaje de bienvenida.
"""
return {"mensaje": "¡Hola, mundo desde FastAPI en Colab!"}
# Petición GET con un parámetro de ruta
@app.get("/items/{item_id}")
async def read_item(item_id: int): # FastAPI valida automáticamente que item_id sea un entero
return {"item_id": item_id, "descripcion": f"Este es el item número {item_id}"}
# Petición GET con parámetro de ruta y parámetro de query opcional
@app.get("/users/{user_id}")
async def read_user(user_id: int, q: Optional[str] = None):
# 'q: Optional[str] = None' significa que 'q' es un string que es opcional y por defecto es None
if q:
return {"user_id": user_id, "query": q, "message": f"Buscando usuario {user_id} con consulta '{q}'"}
return {"user_id": user_id, "message": f"Usuario {user_id} encontrado sin consulta"}
# Definimos un modelo Pydantic para el Item
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
Vicente Simón Rando
(CC BY-NC-ND 4.0)
111 de 115
Manual completo de Python para Principiantes
tax: Optional[float] = None
# Petición POST para crear un nuevo item
@app.post("/items/")
async def create_item(item: Item): # FastAPI espera que el cuerpo de la petición sea un objeto Item
item_dict = item.model_dump() # Convertimos el objeto Item a un diccionario
if item.tax:
price_with_tax = item.price + item.tax
item_dict.update({"price_with_tax": price_with_tax})
return {"message": "Item creado con éxito", "item": item_dict}
class Order(BaseModel):
order_id: int
items: list[Item] # Una lista de objetos Item
customer_name: str
order_date: datetime.datetime # FastAPI sabe cómo serializar esto
total_amount: float
@app.post("/orders/")
async def create_order(order: Order):
# Aquí podrías guardar la orden en una base de datos, etc.
return {
"status": "success",
"message": f"Orden {order.order_id} recibida para {order.customer_name}",
"order_details": order.model_dump() # Convertir el objeto Order a diccionario para la respuesta
}
Colab
# --- Configuración y ejecución de ngrok --# Asegúrate de tener tu token de autenticación de ngrok.
# Puedes obtenerlo en https://dashboard.ngrok.com/auth/your-authtoken
# Es buena práctica no incluir el token directamente en el código.
# Puedes configurarlo como una variable de entorno en Colab o pegarlo aquí.
# Por ejemplo: ngrok.set_auth_token("TU_TOKEN_DE_AUTENTICACION_NGROK")
# Si no quieres exponer tu token directamente, puedes pedirlo al usuario o
# establecerlo como una variable de entorno de Colab.
# Para este ejemplo, lo dejaremos como una cadena vacía para que Colab lo pida si no está configurado.
# Reemplaza "TU_TOKEN_DE_AUTENTICACION_NGROK" con tu token real si lo deseas.
# O, si lo configuras como variable de entorno en Colab:
# from google.colab import userdata
ngrok_auth_token = userdata.get('NGROK_AUTH_TOKEN') # Asegúrate de haber guardado tu token como 'NGROK_AUTH_TOKEN' en
Colab Secrets
if ngrok_auth_token:
ngrok.set_auth_token(ngrok_auth_token)
else:
print("Por favor, configura tu token de autenticación de ngrok. Visita https://dashboard.ngrok.com/auth/yourauthtoken")
# O pide al usuario que lo ingrese
ngrok.set_auth_token(input("Introduce tu token de autenticación de ngrok: "))
# Si no tienes un token, ngrok puede funcionar con limitaciones.
# Es altamente recomendable usar un token para evitar limitaciones de conexión y para un uso más estable.
# Iniciar el túnel ngrok en el puerto 8000 (puerto por defecto de Uvicorn)
# Primero, cierra cualquier túnel ngrok existente para evitar conflictos.
ngrok.kill()
# Inicia un túnel HTTP en el puerto 8000
public_url = ngrok.connect(8000)
print(f"¡Tu aplicación FastAPI está accesible en: {public_url}")
# --- Ejecución de Uvicorn --# Ejecutar la aplicación FastAPI con Uvicorn en un hilo separado
# Esto permite que el túnel ngrok y la aplicación FastAPI se ejecuten concurrentemente.
# La función `run` de uvicorn es bloqueante, por eso necesitamos nest_asyncio.
try:
uvicorn.run(app, host="0.0.0.0", port=8000)
except KeyboardInterrupt:
print("Servidor Uvicorn detenido.")
finally:
# Asegúrate de cerrar el túnel ngrok cuando el servidor se detenga
print("Cerrando túnel ngrok...")
ngrok.kill()
print("Túnel ngrok cerrado.")
E.8. Código Google Colab para crear el cliente
Colab
import requests
# Asegúrate de que 'public_url' contenga la URL pública de ngrok
# Esta variable se crea en el código proporcionado anteriormente.
public_url = input('Pega tu public_url de ngrok aquí (ej. https://xxxxxxxxxxxxx.ngrok.io): ')
Vicente Simón Rando
(CC BY-NC-ND 4.0)
112 de 115
Manual completo de Python para Principiantes
Colab
print(f"Visita el sitio {public_url}/docs para conseguir la documentación de tu API")
Colab
print(f"Visita el sitio {public_url}/redoc para tener otra forma de ver la documentación de tu API")Colab
Colab
if 'public_url' in locals() and public_url:
try:
# Realizar una petición GET a la raíz de la URL pública
response = requests.get(public_url + "/")
# Verificar si la petición fue exitosa (código de estado 200)
if response.status_code == 200:
print("Petición exitosa:")
print(f"Código de estado: {response.status_code}")
print("Cuerpo de la respuesta:")
print(response.json()) # Imprimir el cuerpo de la respuesta en formato JSON
else:
print(f"Error en la petición: Código de estado {response.status_code}")
print(response.text) # Imprimir el cuerpo de la respuesta de error
except requests.exceptions.RequestException as e:
print(f"Error al conectar con la URL: {e}")
else:
print("La variable 'public_url' no está definida o está vacía. Asegúrate de que el túnel ngrok se haya iniciado
correctamente.")
Colab
if 'public_url' in locals() and public_url:
urls_to_test = ["/items/123", "/users/5", "/users/5?q=activo"]
for url_path in urls_to_test:
full_url = public_url + url_path
print(f"\nTesting URL: {full_url}")
try:
response = requests.get(full_url)
if response.status_code == 200:
print("Petición exitosa:")
print(f"Código de estado: {response.status_code}")
print("Cuerpo de la respuesta:")
print(response.json())
else:
print(f"Error en la petición: Código de estado {response.status_code}")
print(response.text)
except requests.exceptions.RequestException as e:
print(f"Error al conectar con la URL: {e}")
else:
print("La variable 'public_url' no está definida o está vacía. Asegúrate de que el túnel ngrok se haya iniciado
correctamente.")
Colab
if 'public_url' in locals() and public_url:
post_url = public_url + "/items/"
post_data = {
"name": "Libro de Python",
"description": "Un gran libro para aprender Python.",
"price": 29.99,
"tax": 0.05
}
print(f"\nTesting POST to URL: {post_url}")
try:
response = requests.post(post_url, json=post_data)
if response.status_code == 200:
print("Petición POST exitosa:")
print(f"Código de estado: {response.status_code}")
print("Cuerpo de la respuesta:")
print(response.json())
else:
print(f"Error en la petición POST: Código de estado {response.status_code}")
print(response.text)
except requests.exceptions.RequestException as e:
print(f"Error al conectar con la URL para POST: {e}")
else:
print("La variable 'public_url' no está definida o está vacía. Asegúrate de que el túnel ngrok se haya iniciado
correctamente.")
Colab
post_data = {
"order_id": 1,
"items": [
{
"name": "Camiseta",
"price": 15.00
},
{
Vicente Simón Rando
(CC BY-NC-ND 4.0)
113 de 115
Manual completo de Python para Principiantes
"name": "Pantalón",
"description": "Pantalón vaquero",
"price": 40.00,
"tax": 0.08
}
],
"customer_name": "Laura García",
"order_date": "2025-07-20T22:30:00.000Z",
"total_amount": 55.00
}
print(f"\nTesting POST to URL: {post_url}")
try:
response = requests.post(post_url, json=post_data)
if response.status_code == 200:
print("Petición POST exitosa:")
print(f"Código de estado: {response.status_code}")
print("Cuerpo de la respuesta:")
print(response.json())
else:
print(f"Error en la petición POST: Código de estado {response.status_code}")
print(response.text)
except requests.exceptions.RequestException as e:
print(f"Error al conectar con la URL para POST: {e}")
else:
print("La variable 'public_url' no está definida o está vacía. Asegúrate de que el túnel ngrok se haya iniciado
correctamente.")
Vicente Simón Rando
(CC BY-NC-ND 4.0)
114 de 115
Manual completo de Python para Principiantes
Despedida
Espero, que si has llegado hasta aquí, este manual te haya sido útil.
Atentamente, Vicente Simón Rando
Vicente Simón Rando
(CC BY-NC-ND 4.0)
115 de 115
0
You can add this document to your study collection(s)
Sign in Available only to authorized usersYou can add this document to your saved list
Sign in Available only to authorized users(For complaints, use another form )