Introducción

Python es un lenguaje de alto nivel cercano al lenguaje natural, interpretado, multiplataforma, scripting y de propósito general. Precisamente, es su cercania con el lenguaje natural lo que facilita su aprendizaje. En este tutorial se realiza un recorrido por los principales tópicos de dicho lenguaje.

Variables y Operadores

Las variables y los operadores son dos conceptos fundamentales en la programación en Python. Las variables se utilizan para almacenar datos, y los operadores se utilizan para realizar operaciones con datos.

Variables

En Python, una variable es un espacio de almacenamiento que tiene un nombre identificador y contiene un valor o referencia a un objeto. Al asignar un valor a una variable, le das un nombre descriptivo que luego puedes utilizar para referenciar y manipular ese valor. La asignación de variables en Python se realiza mediante el operador de asignación =.

A continuación muestro un ejemplo:

# Asignación de variables
nombre = "John"
edad = 25
altura = 1.75
es_estudiante = True

Operadores

Python incluye varios tipos de operadores que permiten realizar operaciones en variables y valores. Aquí hay algunos de los operadores más comunes:

  1. Operadores Aritméticos

    Los operadores aritméticos más comunes son

    • Suma: +

    • Resta: -

    • Multiplicación: *

    • División: /

    • Potenciación: **
  2. Operadores Lógicos

    Los operadores lógicos más comunes son:

    • AND: and

    • OR: or

    • NOT: not
  3. Operadores de Comparación

    Los operadores de comparación más comunes son:

    • Igual: ==

    • Distinto: !=

    • Mayor que: >

    • Menor que: <

    • Mayor o igual que: >=

    • Menor o igual que: <=
  4. Operadores de Asignación

    Los operadores de asignación más comunes son:

    • Suma: +=

    • Resta: -=

    • Multiplicación: *=

    • División: /=

    • Módulo: %=

    • Potenciación: **=

Estructuras de Datos

Las estructuras de datos son contenedores que almacenan datos. Python proporciona una variedad de estructuras de datos, como listas, tuplas, conjuntos y diccionarios.

Listas

Una lista es una estructura de datos que puede almacenar una secuencia de elementos. Los elementos de una lista pueden ser de cualquier tipo de dato, incluidos números, cadenas, objetos y otras listas. Para crear una lista, se usa la corchetes []. Por ejemplo, para crear una lista que almacenará los números 1, 2 y 3, se usaría el siguiente código:

numeros = [1, 2, 3]

Tuplas

Una tupla es una estructura de datos similar a una lista, pero los elementos de una tupla son inmutables. Esto significa que los elementos de una tupla no se pueden modificar una vez que se han asignado. Para crear una tupla, se usa la sintaxis ( y ). Por ejemplo, para crear una tupla que almacenará los números 1, 2 y 3, se usaría el siguiente código:

numeros = (1, 2, 3)

Conjuntos

Un conjunto es una estructura de datos que almacena una colección de elementos únicos. Los elementos de un conjunto no están ordenados y no tienen índices. Para crear un conjunto, se usa la sintaxis {}. Por ejemplo, para crear un conjunto que almacenará los números 1, 2 y 3, se usaría el siguiente código:

numeros = {1, 2, 3}

Diccionarios

Un diccionario es una estructura de datos que permite almacenar y organizar datos de manera eficiente. Se trata de una colección no ordenada de pares clave-valor, donde cada clave debe ser única. Los diccionarios son conocidos también como "mapas" o "tablas hash" en otros lenguajes de programación. Un diccionario en Python se define utilizando llaves {} y tiene la siguiente estructura básica:

personas = { "Juan": 20, "María": 25 }

Control de Flujo

El control de flujo en Python es el proceso de controlar el orden en que se ejecutan las instrucciones de un programa. Se utiliza para determinar qué instrucciones se ejecutan, cuándo se ejecutan y cuántas veces se ejecutan.

Sentencias condicionales

Las sentencias condicionales se utilizan para controlar el flujo del programa en función de una condición. Las sentencias condicionales más comunes en Python son if, elif y else.

Bucles

Los bucles se utilizan para ejecutar un bloque de instrucciones repetidamente. Los bucles más comunes en Python son while, for y se utiliza la palabra break para interrumpir la ejecución del loop y la palabra clave continue para saltar de la actual iteración a la siguiente.

Funciones

Una función es un bloque de código reutilizable que se puede llamar desde cualquier parte del programa. Las funciones se utilizan para dividir un programa en tareas más pequeñas y manejables, y para hacer que el código sea más fácil de leer y mantener.

Para definir una función en Python, se utiliza la palabra clave def seguida del nombre de la función, los parámetros de entrada y el cuerpo de la función. El cuerpo de la función es un bloque de código que se ejecutará cuando se llame a la función.

El siguiente código define una función llamada sum() que suma dos números:

def sum(a, b):
return a + b

La misma función anterior se puede crear utilizando una función anónima lambda y asignarla a una variable:

sum=lambda a, b: a + b

Programación Orientada a Objetos (POO)

La Programación Orientada a Objetos (POO) es un paradigma de programación que organiza el código en torno a objetos. Los objetos son entidades que contienen datos (llamados atributos) y métodos (funciones que se aplican a una instancia de la clase). Los datos son información que el objeto almacena, y los métodos son acciones que el objeto puede realizar.

En Python, la POO se implementa mediante clases. Las clases son plantillas que se utilizan para crear objetos. Las clases definen los datos y los métodos que tendrá un objeto.

El siguiente código define una clase llamada Mascota:

class Mascota:
  def __init__(self, nombre, especie):
    self.nombre = nombre
    self.especie = especie

  def presentarse(self):
    return f"Soy {self.nombre}, una {self.especie}."

mi_mascota = Mascota("Firulais", "perro")
print(mi_mascota.presentarse())

Decoradores

Los decoradores son funciones que se utilizan para modificar el comportamiento de otras funciones. Los decoradores se pueden utilizar para agregar funcionalidad, realizar comprobaciones de seguridad o registrar información sobre la ejecución de una función.

Los decoradores se definen usando la sintaxis siguiente:

@decorador_funcion
def funcion_a_decorar():
  pass


En esta sintaxis, decorador_funcion es la función decoradora, y funcion_a_decorar es la función que se va a decorar. La función decoradora se ejecuta antes de que se ejecute la función a decorar. La función decoradora puede devolver la función a decorar, o puede devolver una función completamente nueva.

def imprimir_nombre_funcion(funcion):
  def wrapper(*args, **kwargs):
    print(funcion.__name__)
    return funcion(*args, **kwargs)
  return wrapper


Este decorador se puede utilizar de la siguiente manera:

@imprimir_nombre_funcion
def saludar(nombre):
  print("Hola, {}!".format(nombre))

Iteradores y Generadores

Los iteradores y generadores son conceptos relacionados que permiten trabajar eficientemente con secuencias de datos, especialmente cuando se trata de conjuntos de datos grandes o cuando queremos generar valores sobre la marcha sin almacenarlos todos en la memoria.

Iteradores:

Un iterador es un objeto que implementa los métodos __iter__() y __next__(). El método __iter__() devuelve el propio objeto iterador, y el método __next__() proporciona el siguiente elemento de la secuencia.
El siguiente es un ejemplo de uso:

class Contador:
  def __init__(self, limite):
    self.limite = limite
    self.valor_actual = 0

  def __iter__(self):
    return self

  def __next__(self):
    if self.valor_actual < self.limite:
      resultado = self.valor_actual
      self.valor_actual += 1
      return resultado
    else:
      raise StopIteration

# Uso del iterador
contador_iterador = Contador(5)
for numero in contador_iterador:
  print(numero)

Generadores:

Los generadores son una forma más sencilla y cómoda de crear iteradores. Se definen mediante funciones que contienen la palabra clave yield. Cuando se llama al generador, la ejecución se pausa en la instrucción yield, y el valor se devuelve al llamante. La próxima vez que se llama al generador, la ejecución se reanuda justo después del yield, manteniendo el estado interno.

El siguiente es un ejemplo de uso:

def generador_pares(n):
  for i in range(0, n, 2):
    yield i
# Uso del generador
for num in generador_pares(6):
  print(num)


En este ejemplo, el generador generador_pares produce números pares hasta el límite n. Cada vez que se itera sobre el generador, la ejecución se pausa en el yield y se reanuda cuando se solicita el siguiente valor.

Módulos y Paquetes

Los módulos y paquetes son mecanismos que permiten organizar y estructurar el código de manera más eficiente, facilitando la reutilización y el mantenimiento del código.

Módulos:

Un módulo en Python es simplemente un archivo que contiene código Python, ya sea funciones, clases o variables. Un módulo puede ser importado en otro script o programa, permitiendo así la reutilización de código.

Ejemplo de Módulo:

Supongamos que tenemos un archivo llamado operaciones.py con el siguiente contenido:

# operaciones.py
def suma(a, b):
     return a + b
def resta(a, b):
     return a - b

Este archivo se puede considerar un módulo. Para usar las funciones definidas en este módulo en otro archivo, simplemente lo importamos:

# otro_script.py
import operaciones
resultado_suma = operaciones.suma(5, 3)
resultado_resta = operaciones.resta(10, 4)

print("Suma:", resultado_suma)
print("Resta:", resultado_resta)

Paquetes

Un paquete en Python es una forma de organizar múltiples módulos relacionados en un directorio. Un paquete debe contener un archivo especial llamado __init__.py para que Python lo reconozca como un paquete.

Ejemplo de Paquete:

Supongamos que tenemos una estructura de directorios como esta:

mi_paquete/
|-- __init__.py
|-- operaciones/
|-|-- __init__.py
|-|-- suma.py
|-|-- resta.py
|-- otro_script.py

Los archivos suma.py y resta.py contienen las funciones de mi_suma y mi_resta, respectivamente. El contenido de __init__.py (tanto en mi_paquete como en operaciones) puede ser un archivo vacío o contener código que se ejecuta cuando el paquete o módulo se importa.

# otro_script.py
from mi_paquete.operaciones import suma, resta

resultado_suma = suma.mi_suma(5, 3)
resultado_resta = resta.mi_resta(10, 4)

print("Suma:", resultado_suma)
print("Resta:", resultado_resta)

También puede ser realizado de la siguiente manera:

# otro_script.py
from mi_paquete.operaciones.suma import mi_suma
from mi_paquete.operaciones.resta import mi_resta

resultado_suma = mi_suma(5, 3)
resultado_resta = mi_resta(10, 4)

print("Suma:", resultado_suma)
print("Resta:", resultado_resta)

Los módulos y paquetes son esenciales para estructurar proyectos más grandes y facilitar la reutilización del código en Python.

Manejo de Excepciones

El manejo de excepciones en Python se refiere a la práctica de gestionar y responder a situaciones excepcionales o errores durante la ejecución de un programa. Las excepciones son eventos que pueden ocurrir durante la ejecución y que pueden interrumpir el flujo normal del programa si no se manejan adecuadamente. El manejo de excepciones permite a los programadores anticipar y gestionar estas situaciones excepcionales, evitando que el programa se bloquee o produzca resultados incorrectos.

En Python, el manejo de excepciones se realiza mediante bloques try, except, else y finally. La estructura básica es la siguiente:

try:
    # Código que puede generar una excepción
    resultado = dividir(10, 0)
except ZeroDivisionError:
    # Manejo específico para la excepción ZeroDivisionError
    print("Error: No se puede dividir por cero.")
except Exception as e:
     # Manejo genérico para otras excepciones
     print(f"Error inesperado: {e}")
else:
     # Se ejecuta si no hay excepciones
     print("La división se realizó con éxito.")
finally:
     # Se ejecuta siempre, independientemente de si se produjo una excepción o no
     print("Este bloque se ejecuta siempre.")

En este ejemplo se tiene lo siguiente:

  • El código dentro del bloque try es susceptible a lanzar una excepción.

  • Los bloques except especifican cómo manejar excepciones particulares. En este caso, se maneja la excepción ZeroDivisionError y, de manera más genérica, Exception.

  • El bloque else se ejecuta si no se produce ninguna excepción en el bloque try.

  • El bloque finally se ejecuta siempre, independientemente de si se produjo una excepción o no. Es útil para realizar acciones de limpieza o liberación de recursos.

Expresiones Regulares

Las expresiones regulares (también conocidas como regex o regexp) son patrones de búsqueda de texto que se utilizan para realizar operaciones de búsqueda y manipulación en cadenas de texto. En Python, las expresiones regulares se implementan a través del módulo re, que proporciona funciones para trabajar con estas expresiones.

Las expresiones regulares son extremadamente poderosas y flexibles, permitiendo buscar patrones específicos, realizar sustituciones, validar formatos y más.

Sintaxis Básica de Expresiones Regulares en Python:

  1. Raw Strings (cadenas sin procesar): En Python, se recomienda utilizar cadenas sin procesar (precedidas por r) al trabajar con expresiones regulares, ya que evitan la necesidad de duplicar barras invertidas (\) para escapar caracteres especiales.

    patron = r"\d{3}-\d{2}-\d{4}"


  2. Metacaracteres Comunes:

    • .: Coincide con cualquier carácter excepto una nueva línea.

    • ^: Coincide con el inicio de una cadena.

    • $: Coincide con el final de una cadena.

    Este es un ejemplo de uso de ^:

    import re
    texto = "Hola, mundo!"

    # Buscar la palabra "Hola" al principio de la cadena
    resultado = re.search(r"^Hola", texto)


  3. Cuantificadores:

    • * : Coincide con 0 o más repeticiones del carácter anterior.

    • + : Coincide con 1 o más repeticiones del carácter anterior.

    • ? : Coincide con 0 o 1 repetición del carácter anterior.

    • {m,n} : Coincide con entre m y n repeticiones del carácter anterior.

  4. Clases de Caracteres:

    • [...] : Coincide con cualquier carácter dentro de los corchetes.

    • [^...] : Coincide con cualquier carácter que no esté dentro de los corchetes.

Estos son solo algunos ejemplos básicos. Las expresiones regulares pueden volverse bastante complejas y son una herramienta poderosa para la manipulación de cadenas de texto. La biblioteca re en Python proporciona varias funciones, como search, match, findall, sub, entre otras, para trabajar con expresiones regulares.

Manipulación de Archivos

La manipulación de archivos en Python se refiere a la capacidad del lenguaje para realizar operaciones de lectura, escritura y manipulación de archivos en el sistema de archivos del sistema operativo. Python posee la función open para interactuar con archivos de texto y binarios.

Ejemplos de Manipulación de Archivos:

  1. Lectura de un Archivo de Texto:

    # Abrir un archivo en modo de lectura
    with open("archivo.txt", "r") as archivo:
      # Leer todo el contenido del archivo
      contenido = archivo.read()
      print(contenido)

    # O leer línea por línea
    archivo.seek(0) # Reiniciar el puntero del archivo al principio
    lineas = archivo.readlines()
    for linea in lineas:
      print(linea.strip()) # Eliminar caracteres de nueva línea al final

  2. Escritura en un Archivo de Texto:

    # Abrir un archivo en modo de escritura
    with open("nuevo_archivo.txt", "w") as archivo:
      # Escribir contenido en el archivo
      archivo.write("Hola, este es un nuevo archivo.\n")
      archivo.write("Línea 2: Contenido adicional.")

  3. Manipulación de Archivos Binarios:

    # Leer y escribir archivos binarios
    with open("imagen.jpg", "rb") as archivo_entrada:
      datos_binarios = archivo_entrada.read()
      with open("copia_imagen.jpg", "wb") as archivo_salida:
          archivo_salida.write(datos_binarios)

  4. Uso de la Instrucción with para Garantizar el Cierre del Archivo:

    La instrucción with asegura que el archivo se cierre adecuadamente después de que se complete el bloque de código. Esto es útil para prevenir posibles problemas de manejo de archivos y para liberar recursos.

    with open("archivo.txt", "r") as archivo:
      # Realizar operaciones de lectura
      contenido = archivo.read()
      print(contenido)
    # El archivo se cerrará automáticamente al salir del bloque 'with'


Estos son solo ejemplos básicos. Además de los modos de lectura y escritura ("r" ,"w" ), existen otros modos como "a" (para añadir al final del archivo) y "b" (para modo binario). También puedes utilizar la biblioteca os para operaciones más avanzadas en archivos y directorios.

Recordar manejar excepciones, como FileNotFoundError al abrir archivos, para garantizar la robustez del código.

Trabajo con API REST

El trabajo con API REST en Python implica interactuar con servicios web que siguen los principios de arquitectura REST (Transferencia de Estado Representacional). Las API REST utilizan operaciones HTTP estándar (GET, POST, PUT, DELETE) para realizar acciones sobre recursos, y los datos se suelen enviar y recibir en formato JSON.

A continuación, se muestra un ejemplo básico de cómo realizar solicitudes a una API REST utilizando el módulo requests en Python.

Ejemplo de Trabajo con API REST:

import requests

# Ejemplo de una API pública (JSONPlaceholder: Fake Online REST API for Testing and Prototyping)

url = "https://jsonplaceholder.typicode.com/posts/1"

# Realizar una solicitud GET para obtener un recurso
response = requests.get(url)

# Verificar si la solicitud fue exitosa (código de estado 200)
if response.status_code == 200:
  # Convertir la respuesta a formato JSON
  datos = response.json()
  print("Título del post:", datos["title"])
else:
  print("Error en la solicitud:",response.status_code)

En el ejemplo anterior se realiza lo siguiente:

  1. Se utiliza la biblioteca requests para realizar una solicitud HTTP GET a la API pública JSONPlaceholder.

  2. Se verifica el código de estado de la respuesta. Un código de estado 200 indica que la solicitud fue exitosa.

  3. Si la solicitud fue exitosa, se convierten los datos de la respuesta a formato JSON y se imprime el título del post.

Ejemplo de Envío de Datos con una Solicitud POST:

import requests
# Ejemplo de una API pública para crear un nuevo recurso
url = "https://jsonplaceholder.typicode.com/posts"

# Datos a enviar en la solicitud POST
datos_nuevo_post = {
  "title": "Nuevo Post",
  "body": "Contenido del nuevo post",
  "userId": 1
}

# Realizar una solicitud POST para crear un nuevo recurso
response = requests.post(url, json=datos_nuevo_post)

# Verificar si la solicitud fue exitosa (código de estado 201 para creación exitosa)
if response.status_code == 201:
  nuevo_post = response.json()
  print("Nuevo Post creado. ID:",nuevo_post["id"])
else:
  print("Error en la solicitud:",response.status_code)

En este ejemplo, se realiza una solicitud HTTP POST para crear un nuevo post en la API JSONPlaceholder enviando datos en formato JSON.

Estos son ejemplos básicos, y trabajar con API REST puede involucrar autenticación, manejo de parámetros, paginación y más, dependiendo de la API específica con la que estés interactuando.