Blog

Programación con Python: Ficheros

Trabajar con ficheros es esencial para leer y escribir datos en el sistema de archivos de nuestro ordenador. A continuación mostraremos la sintaxis básica para utilizar ficheros en Python, incluyendo cómo abrir, leer y escribir en ellos. Utilizaremos explicaciones acompañadas de ejercicios prácticos.

Abrir y cerrar ficheros

Para trabajar con un archivo en Python, primero debemos abrirlo. Podemos usar la función open() para abrir un archivo en diferentes modos, como lectura ('r') o escritura ('w') y también para añadir ('a'). Después de terminar de trabajar con el fichero, debemos cerrarlo utilizando el método close() para liberar recursos y también para evitar la pérdida de datos:

# Abrir un archivo en modo de lectura
archivo = open("archivo.txt", "r")

# Trabajar con el archivo (leer o escribir)

# Cerrar el archivo después de terminar
archivo.close()

Leer contenido de un fichero

Para leer el contenido de un archivo, podemos usar los métodos read(), readline() o readlines():

  • read(). Lee todo el contenido del archivo como una cadena de texto:
archivo = open("archivo.txt", "r")
contenido = archivo.read()
print(contenido)
archivo.close()
  • readline(). Lee una línea del archivo:
archivo = open("archivo.txt", "r")
linea = archivo.readline()
print(linea)
archivo.close()
  • readlines(). Lee todas las líneas del archivo y las devuelve como una lista:
archivo = open("archivo.txt", "r")
lineas = archivo.readlines()
print(lineas)
archivo.close()

Escribir en un archivo

Para escribir en un archivo, debemos abrirlo en modo de escritura, con 'w' o para añadir, con 'a', según lo que necesitemos en cada momento:

  • Modo escritura ('w'). Sobrescribe el contenido del archivo existente o crea un nuevo archivo si no existe:
archivo = open("archivo.txt", "w")
archivo.write("Este es un nuevo contenido.\n")
archivo.write("¡Hola, Mundo!\n")
archivo.close()
  • Modo añadir ('a'). Agrega contenido al final del archivo existente o crea un nuevo archivo si no existe:
archivo = open("archivo.txt", "a")
archivo.write("Este es un contenido adicional.\n")
archivo.write("¡Hola de nuevo!\n")
archivo.close()

Gestores de contexto

El uso de un gestor de contexto con la declaración with es una forma más segura y eficiente de trabajar con ficheros. Utilizando esta funcionalidad, el archivo se cierra automáticamente cuando el bloque with termina, incluso si se produce una excepción:

# Leer contenido del archivo con un Context Manager
with open("archivo.txt", "r") as archivo:
    contenido = archivo.read()
    print(contenido)

# Escribir en el archivo con un Context Manager
with open("archivo.txt", "a") as archivo:
    archivo.write("Esto es un nuevo contenido con Context Manager.\n")

Verificar si un archivo existe

Podemos usar el módulo os para verificar si un archivo existe antes de abrirlo.

import os

nombre_archivo = "archivo.txt"

if os.path.exists(nombre_archivo):
    with open(nombre_archivo, "r") as archivo:
        contenido = archivo.read()
        print(contenido)
else:
    print(f"El archivo '{nombre_archivo}' no existe.")

Programación con Python: Funciones

Las funciones son bloques de código reutilizables en Python que pueden tener argumentos de entrada, realizar un conjunto de acciones y devolver un resultado. Son una parte fundamental de la programación, ya que nos permiten dividir tareas complejas en piezas más pequeñas y organizadas. A continuación analizaremos la sintaxis básica de las funciones en Python, con explicaciones y ejemplos prácticos.

Definición de funciones

En Python podemos definir una función utilizando la palabra clave def, seguida del nombre de la función y los paréntesis de apertura y cierre, que pueden contener los argumentos de la función. A continuación debemos añadir dos puntos : y el bloque de código que forma el cuerpo de la función:

def saludar():
    print("¡Hola! Bienvenido.")

Llamadas a funciones

Para ejecutar el código de la función simplemente debemos realizar una llamada utilizando su nombre seguido de paréntesis:

def saludar():
    print("¡Hola!")

saludar()  # Salida: ¡Hola!

Argumentos de funciones

Las funciones pueden aceptar argumentos de entrada, que son valores que se pasan a la función cuando se llama. Los parámetros que recibirán esos argumentos se escriben entre paréntesis en la definición de la función:

def saludar(nombre):
    print(f"¡Hola, {nombre}!")

saludar("Juan")   # Salida: ¡Hola, Juan!
saludar("María")  # Salida: ¡Hola, María!

Parámetros con valores predeterminados

Podemos asignar valores predeterminados a los parámetros de una función. Si un valor no se proporciona al llamar a la función, se utilizará el valor predeterminado:

def saludar(nombre="Invitado"):
    print(f"¡Hola, {nombre}!")

saludar()          # Salida: ¡Hola, Invitado!
saludar("Carlos")  # Salida: ¡Hola, Carlos!

Parámetros posicionales

Los parámetros posicionales son la forma más básica y común de pasar argumentos a una función en Python. Estos parámetros reciben sus valores en el orden en que son pasados cuando se llama a la función:

def nombre_de_funcion(parametro1, parametro2, parametro3):
    # Cuerpo de la función
    # Podemos usar los parámetros dentro de la función
    print(parametro1, parametro2, parametro3)

nombre_de_funcion("a", "b", "c") # Salida: a b c

Por ejemplo, si queremos realizar una división entre dos números, podemos definir los parámetros posicionales a y b de la función dividir(). Cuando llamamos a la función dividir(10, 5), los valores 10 y 5 se asignan a los parámetros a y b, respectivamente:

def dividir(a, b):
    resultado = a / b
    return resultado

resultado = dividir(10, 5)
print(resultado)  # Salida: 2.0

Orden de los argumentos en una función

El orden de los argumentos en una función es esencial cuando se utilizan parámetros posicionales. Si cambiamos el orden, los valores se asignarán a los parámetros de forma diferente y la función puede no producir los resultados esperados:

def restar(a, b):
    resultado = a - b
    return resultado

resultado_resta1 = restar(10, 3)
print(resultado_resta1)  # Salida: 7

resultado_resta2 = restar(3, 10)
print(resultado_resta2)  # Salida: -7

En el segundo caso, se asignaron los valores 3 y 10 a a y b, respectivamente. Como la operación en la función es a - b, obtuvimos -7 en lugar de 7.

Orden de los parámetros en la definición de la función

El orden en que definamos los parámetros posicionales en la declaración de la función también es importante. En el siguiente ejemplo definimos la función potencia , recibiendo los parámetros (a, b) en el primer caso, y (b, a) en el segundo:

def potencia(a, b):
    resultado = a ** b
    return resultado

resultado1 = potencia(2, 3)
print(resultado1)  # Salida: 8

# Cambio en el orden de los parámetros
def potencia(b, a):
    resultado = a ** b
    return resultado

resultado2 = potencia(2, 3)
print(resultado2)  # Salida: 9

En el segundo caso, se asignaron los valores 3 y 2 a a y b, respectivamente. Como la operación en la función es a ** b, obtuvimos 9 en lugar de 8.

Parámetros nominales

Los parámetros nominales son una característica relativamente nueva en Python que se introdujo en la versión 3.8. Nos permiten pasar argumentos a una función utilizando sus nombres en lugar de su posición. Esto puede hacer que el código sea más legible y menos propenso a errores, especialmente cuando tenemos muchas opciones de argumentos o valores predeterminados en una función.

Para definir una función con parámetros nominales, debemos usar un símbolo de igual = después del nombre del parámetro y proporcionar un valor predeterminado:

def saludar(nombre="Invitado", apellido=""):
    print(f"¡Hola, {nombre}!")

saludar(nombre="Juan", apellido="Ruiz")    # Salida: ¡Hola, Juan Ruiz!
saludar(apellido="Rubio", nombre="María")  # Salida: ¡Hola, María Rubio!

# En la siguiente llamada se usarán los valores predeterminados
saludar()  # Salida: ¡Hola, Invitado!

En el ejemplo, la función saludar tiene dos parámetros nominales nombre y apellido, con valores predeterminados establecidos. Podemos llamar a la función pasando los argumentos utilizando sus nombres. Esto hace que el orden de los argumentos no sea relevante y permite que el código sea más claro.

Los parámetros nominales también son útiles cuando una función tiene muchos argumentos, algunos de los cuales pueden tener valores predeterminados que no deseas cambiar. En lugar de pasar valores específicos para todos los argumentos, simplemente pasas los valores que necesitas cambiar.

Paso de argumentos variables

Si no estamos seguro de cuántos argumentos recibirás, puedes utilizar *args para pasar un número variable de argumentos posicionales y **kwargs para pasar un número variable de argumentos clave-valor:

def funcion(*args, **kwargs):
    print(args)     # Una tupla con argumentos posicionales
    print(kwargs)   # Un diccionario con argumentos clave-valor

funcion(1, 2, 3, nombre="Ana", edad=30)
# Salida:
# (1, 2, 3)
# {'nombre': 'Ana', 'edad': 30}

Valor de retorno

Las funciones pueden devolver un valor utilizando la palabra clave return. Esto es útil cuando queremos que una función realice un cálculo o una tarea y devuelva el resultado para su posterior uso:

def sumar(a, b):
    resultado = a + b
    return resultado

resultado_suma = sumar(3, 5)
print(resultado_suma)  # Salida: 8

Podemos devolver múltiples valores utilizando la instrucción return con una tupla:

def calcular(a, b):
    suma = a + b
    resta = a - b
    multiplicacion = a * b
    return suma, resta, multiplicacion

resultado = calcular(10, 5)
print(resultado)  # Salida: (15, 5, 50)

Además, podemos definir el valor y el tipo que devolverá la función dependiendo del flujo de código. A continuación vamos a ver un ejemplo más complejo donde utilizamos una sentencia match case para calcular el área de diferentes figuras geométricas, y devolvemos el resultado como valor de retorno. Vamos a crear una función llamada calcular_area que recibe el nombre de la figura geométrica («cuadrado», «rectángulo», «círculo» o «triángulo») y las medidas necesarias para calcular el área. Dependiendo del caso, el match case realiza el cálculo del área y lo utiliza como valor de retorno de la función. Incluso contemplamos la posibilidad de que la figura que se reciba como parámetro no exista, en cuyo caso se devolverá el valor por defecto con el tipo None:

def calcular_area(figura, medida1, medida2=None):
    match figura:
        case "cuadrado":
            return medida1 ** 2
        case "rectangulo":
            return medida1 * medida2
        case "circulo":
            return 3.1416 * medida1 ** 2
        case "triangulo":
            return 0.5 * medida1 * medida2
        case _:
            return None

area_cuadrado = calcular_area("cuadrado", 5)
area_rectangulo = calcular_area("rectangulo", 4, 6)
area_circulo = calcular_area("circulo", 3)
area_triangulo = calcular_area("triangulo", 2, 8)

print("Área del cuadrado:", area_cuadrado)     # Área del cuadrado: 25
print("Área del rectángulo:", area_rectangulo) # Área del rectángulo: 24
print("Área del círculo:", area_circulo)       # Área del círculo: 28.2744
print("Área del triángulo:", area_triangulo)   # Área del triángulo: 8.0

En este último ejemplo, el match case nos permite realizar los cálculos del área de diferentes formas geométricas de manera sencilla y legible. Cada caso corresponde a una forma geométrica específica, y el resultado se calcula utilizando las medidas proporcionadas. Al utilizar el match case, evitamos la necesidad de utilizar una serie de sentencias if-elif-else para identificar la forma geométrica y realizar el cálculo correspondiente. El código resultante es más limpio y más claro.

Ámbito de variables

Las variables declaradas dentro de una función tienen un alcance local y solo existen dentro de la función:

def funcion():
    variable_local = "Soy local"
    print(variable_local)

funcion()  # Salida: Soy local

# La siguiente línea generaría un error ya que variable_local no está definida en este ámbito
# print(variable_local)

Las variables declaradas fuera de una función tienen un alcance global y son accesibles desde cualquier parte del programa. Si queremos utilizar una variable global dentro de una función, debemos usar la palabra clave global antes de la variable:

contador_global = 0

def incrementar_contador():
    global contador_global
    contador_global += 1

incrementar_contador()
print(contador_global)  # Salida: 1

Funciones anidadas

Podemos definir funciones dentro de otras funciones, lo que se conoce como funciones anidadas:

def funcion_principal():
    print("Función principal")

    def funcion_anidada():
        print("Función anidada")

    funcion_anidada()

funcion_principal()
# Salida:
# Función principal
# Función anidada

Funciones lambda

Las funciones lambda son funciones anónimas y pequeñas que pueden tener cualquier número de parámetros, pero solo pueden tener una expresión. Se definen utilizando la palabra clave lambda:

# Función lambda que devuelve el cuadrado de un número
cuadrado = lambda x: x ** 2

resultado = cuadrado(5)
print(resultado)  # Salida: 25

Programación con Python: Diccionarios

Los diccionarios de Python son una estructura de datos extremadamente útil y versátil, ya que permiten almacenar y organizar datos en pares clave-valor. Cada elemento en un diccionario está compuesto por una clave única y su valor correspondiente. Los diccionarios son ampliamente utilizados en el desarrollo de aplicaciones, y su capacidad para manejar datos complejos y anidados los convierte en una herramienta esencial. A continuación explicaremos la funcionalidad básica sobre diccionarios en Python, con explicaciones y ejemplos prácticos.

Creación de diccionarios

Podemos crear un diccionario en Python encerrando los pares clave-valor entre llaves {}. Cada par clave-valor se separa por dos puntos : y los pares se separan por comas:

# Diccionario vacío
diccionario_vacio = {}

# Diccionario de personas y sus edades
personas_edades = {"Juan": 30, "María": 25, "Carlos": 35}

# Diccionario con diferentes tipos de valores
datos = {"nombre": "Ana", "edad": 28, "es_estudiante": True}

Acceso a elementos

Podemos acceder a los valores de un diccionario utilizando sus claves. Para ello, podemos emplear la sintaxis nombre_diccionario[clave]:

personas_edades = {"Juan": 30, "María": 25, "Carlos": 35}

edad_juan = personas_edades["Juan"]    # 30
edad_maria = personas_edades["María"]  # 25

Si intentamos acceder a una clave que no existe en el diccionario, se generará un error. Para evitarlo, podemos usar el método get(), que permite obtener el valor de la clave o un valor predeterminado si la clave no existe:

personas_edades = {"Juan": 30, "María": 25, "Carlos": 35}

edad_juan = personas_edades.get("Juan")       # 30
edad_pedro = personas_edades.get("Pedro", 0)  # 0 (Pedro no está en el diccionario)

Modificación de elementos

Podemos modificar los valores de un diccionario utilizando la clave correspondiente:

personas_edades = {"Juan": 30, "María": 25, "Carlos": 35}

personas_edades["Juan"] = 32
personas_edades["María"] = 26

print(personas_edades)  # {"Juan": 32, "María": 26, "Carlos": 35}

Añadir elementos

Podemos añadir nuevos elementos a un diccionario simplemente asignando un nuevo par clave-valor:

personas_edades = {"Juan": 30, "María": 25}

personas_edades["Carlos"] = 35

print(personas_edades)  # {"Juan": 30, "María": 25, "Carlos": 35}

Eliminar elementos

Podemos eliminar elementos de un diccionario utilizando la palabra clave del seguida de la clave del elemento que queramos eliminar:

personas_edades = {"Juan": 30, "María": 25, "Carlos": 35}

del personas_edades["Juan"]

print(personas_edades)  # {"María": 25, "Carlos": 35}

Funciones y métodos disponibles para diccionarios

Los diccionarios en Python vienen acompañados con varios métodos útiles.

len()

La función len() nos permite obtener la cantidad de elementos (pares clave-valor) en el diccionario:

personas_edades = {"Juan": 30, "María": 25, "Carlos": 35}

cantidad_elementos = len(personas_edades)  # 3

keys(), values() e items()

Estos métodos permiten obtener las claves, los valores y los pares clave-valor del diccionario, respectivamente:

personas_edades = {"Juan": 30, "María": 25, "Carlos": 35}

claves = personas_edades.keys()              # dict_keys(['Juan', 'María', 'Carlos'])
valores = personas_edades.values()           # dict_values([30, 25, 35])
pares_clave_valor = personas_edades.items()  # dict_items([('Juan', 30), ('María', 25), ('Carlos', 35)])

pop()

El método pop() nos permite eliminar un elemento del diccionario y devolver su valor. También podemos proporcionar un valor predeterminado si la clave no existe en el diccionario:

personas_edades = {"Juan": 30, "María": 25, "Carlos": 35}

edad_carlos = personas_edades.pop("Carlos")   # 35
edad_pedro = personas_edades.pop("Pedro", 0)  # 0 (Pedro no está en el diccionario)

update()

El método update() nos permite fusionar un diccionario con otro. Si una clave existe en el diccionario original y en el diccionario que se está fusionando, el valor de la clave en el diccionario original se actualizará con el valor correspondiente del diccionario que se está fusionando. Si la clave no existe en el diccionario original, se agregará al diccionario junto con su valor:

diccionario1 = {"a": 1, "b": 2}
diccionario2 = {"b": 3, "c": 4}

diccionario1.update(diccionario2)

print(diccionario1)  # {'a': 1, 'b': 3, 'c': 4}

clear()

El método clear() nos permite eliminar todos los elementos del diccionario, dejándolo vacío:

personas_edades = {"Juan": 30, "María": 25, "Carlos": 35}

personas_edades.clear()

print(personas_edades)  # {}

Iteración en diccionarios

Podemos utilizar un bucle for para iterar sobre las claves o los elementos de un diccionario:

personas_edades = {"Juan": 30, "María": 25, "Carlos": 35}

# Iterar sobre las claves
for clave in personas_edades:
    print(clave)

# Iterar sobre los valores
for valor in personas_edades.values():
    print(valor)

# Iterar sobre los pares clave-valor
for clave, valor in personas_edades.items():
    print(f"{clave}: {valor}")

Comprobación de existencia en diccionarios

Podemos utilizar el operador in para comprobar si una clave existe en un diccionario:

personas_edades = {"Juan": 30, "María": 25, "Carlos": 35}

if "Juan" in personas_edades:
    print("La clave 'Juan' está en el diccionario.")

Diccionarios anidados

En Python, los diccionarios pueden estar anidados, es decir, podemos tener diccionarios dentro de diccionarios:

personas = {
    "Juan": {"edad": 30, "ciudad": "Madrid"},
    "María": {"edad": 25, "ciudad": "Barcelona"},
    "Carlos": {"edad": 35, "ciudad": "Sevilla"}
}

print(personas["Juan"]["edad"])     # 30
print(personas["María"]["ciudad"])  # "Barcelona"

Diccionarios y comprensión

También podemos utilizar la comprensión de diccionarios para crear diccionarios de manera muy simple. Por ejemplo, podemos crear un diccionario donde las claves son los números de una lista y los valores son el cuadrado de esos números:

numeros = [1, 2, 3, 4, 5]
diccionario_numeros = {numero: numero**2 for numero in numeros}

print(diccionario_numeros)  # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

Diccionarios como argumentos de funciones

Los diccionarios son útiles cuando queremos pasar un número variable de argumentos a una función, tal como veremos en la unidad específica de funciones. En el siguiente ejemplo utilizamos **datos para indicar que la función aceptará un número variable de argumentos clave-valor y luego iteramos sobre los elementos del diccionario datos:

def imprimir_datos(**datos):
    for clave, valor in datos.items():
        print(f"{clave}: {valor}")

imprimir_datos(nombre="Ana", edad=28, ciudad="Madrid")
# Salida:
# nombre: Ana
# edad: 28
# ciudad: Madrid

Programación con Python: Tuplas

Las tuplas en Python son una estructura de datos que se utiliza para almacenar colecciones de elementos, pero a diferencia de las listas, las tuplas son inmutables, lo que significa que una vez que se crean, no pueden modificarse. A continuación mostraremos la funcionalidad básica que nos proporcionan las tuplas en Python, con explicaciones y ejemplos prácticos.

Creación de tuplas

Podemos crear una tupla en Python encerrando elementos entre paréntesis ():

# Tupla vacía
tupla_vacia = ()

# Tupla de números enteros
numeros_enteros = (1, 2, 3, 4, 5)

# Tupla de números flotantes
numeros_flotantes = (1.5, 2.25, 3.75)

# Tupla de cadenas de texto
nombres = ("Ana", "Carlos", "María")

# Tupla con elementos de diferentes tipos
mixta = (10, "Python", True, 3.14)

También podemos crear una tupla sin usar paréntesis, simplemente separando los elementos por comas. Esto se conoce como «tupla implícita»:

tupla = 1, 2, 3

Acceso a elementos

Podemos acceder a los elementos de una tupla utilizando índices, al igual que con las listas. El primer elemento tiene un índice de 0 y el último de -1:

numeros = (10, 20, 30, 40, 50)

primer_elemento = numeros[0]   # 10
segundo_elemento = numeros[1]  # 20
ultimo_elemento = numeros[-1]  # 50 (índice negativo para acceder al último elemento)

Inmutabilidad de las tuplas

La principal diferencia entre las listas y las tuplas es que las tuplas son inmutables. Si necesitamos una estructura de datos que no cambie, podemos usar tuplas en lugar de listas para evitar modificaciones accidentales. Una vez que se crea una tupla, no podemos modificar sus elementos ni agregar nuevo contenido:

tupla = (1, 2, 3)

tupla[0] = 10  # Esto dará un error, ya que no se pueden modificar los elementos de una tupla

tupla.append(4)  # Esto también dará un error, ya que no se pueden agregar elementos a una tupla

Operaciones con tuplas

Longitud de la tupla

Podemos obtener la longitud de una tupla utilizando la función len():

numeros = (1, 2, 3, 4, 5)
longitud = len(numeros)  # 5

Concatenación de tuplas

Podemos concatenar dos o más tuplas utilizando el operador +:

tupla1 = (1, 2, 3)
tupla2 = (4, 5, 6)
concatenada = tupla1 + tupla2  # (1, 2, 3, 4, 5, 6)

Repetición de tuplas

Podemos repetir una tupla utilizando el operador *:

tupla = (1, 2, 3)
repetida = tupla * 3  # (1, 2, 3, 1, 2, 3, 1, 2, 3)

Búsqueda en tuplas

Podemos buscar elementos en una tupla utilizando el operador in:

numeros = (1, 2, 3, 4, 5)

existe_3 = 3 in numeros  # True
existe_6 = 6 in numeros  # False

Troceado de tuplas (slicing)

Al igual que con las listas, podemos obtener subtuplas (slices) de una tupla utilizando la sintaxis [inicio:fin]:

numeros = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

sub_tupla = numeros[2:6]  # (3, 4, 5, 6)

tupla_inversa = numeros[::-1]  # (10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

Métodos disponibles para las tuplas

Dado que las tuplas son inmutables, no tienen muchos métodos incorporados como las listas. Sin embargo, tienen dos métodos principales:

count()

La función count() nos permite contar cuántas veces aparece un elemento en una tupla:

tupla = (1, 2, 2, 3, 4, 2)
contador = tupla.count(2)  # 3 (el número 2 aparece 3 veces en la tupla)

index()

La función index() nos permite encontrar el índice de la primera aparición de un elemento en una tupla:

tupla = (10, 20, 30, 40, 50)
indice = tupla.index(30)  # 2 (el número 30 está en el índice 2 de la tupla)

Convertir tuplas en listas y viceversa

Si necesitamos modificar una tupla, podemos convertirla en una lista, realizar las modificaciones y luego convertirla de nuevo en una tupla:

tupla = (1, 2, 3)
lista = list(tupla)  # [1, 2, 3]

# Realizar modificaciones en la lista (agregar o eliminar elementos)
lista.append(4)  # [1, 2, 3, 4]

# Convertir la lista de vuelta en una tupla
tupla_modificada = tuple(lista)  # (1, 2, 3, 4)

Por otro lado, si tenemos una lista y queremos evitar modificaciones, podemos convertirla en una tupla:

lista = [1, 2, 3]
tupla = tuple(lista)  # (1, 2, 3)

Desempaquetado de tuplas

Podemos desempaquetar los elementos de una tupla en variables individuales:

tupla = (10, 20, 30)
a, b, c = tupla

print(a)  # 10
print(b)  # 20
print(c)  # 30

El desempaquetado de tuplas también se puede usar para intercambiar valores de variables de manera sencilla:

a = 10
b = 20

# Intercambiar los valores de a y b utilizando una tupla
a, b = b, a

print(a)  # 20
print(b)  # 10

Iterar sobre tuplas

Podemos utilizar un bucle for para iterar sobre los elementos de una tupla de manera similar a las listas:

numeros = (1, 2, 3, 4, 5)

for numero in numeros:
    print(numero)

Comprobación de existencia en tuplas

Al igual que con las listas, podemos utilizar el operador in para comprobar si un elemento está presente en una tupla:

numeros = (1, 2, 3, 4, 5)

if 3 in numeros:
    print("El número 3 está en la tupla.")

Tuplas y funciones

A continuación enumeramos algunas ventajas adicionales asociadas al uso de funciones y otros tipos de estructuras de datos que veremos de forma detallada en otras unidades. Hemos creído conveniente exponerlas ahora para ser conscientes del gran potencial que presentan las tuplas de Python.

Retorno de valores

Las tuplas son útiles cuando queremos devolver múltiples valores desde una función:

def dividir_y_restar(a, b):
    division = a / b
    resta = a - b
    return division, resta

resultado = dividir_y_restar(10, 3)
print(resultado)  # (3.3333333333333335, 7)

# Desempaquetar los valores de la tupla en variables separadas
division_resultado, resta_resultado = dividir_y_restar(10, 3)
print(division_resultado)  # 3.3333333333333335
print(resta_resultado)  # 7

Tuplas y funciones con argumentos variables

Las tuplas también son útiles cuando trabajamos con funciones que aceptan argumentos variables:

def suma_todos(*numeros):
    total = sum(numeros)
    return total

resultado = suma_todos(1, 2, 3, 4, 5)
print(resultado)  # 15

# También podemos pasar una tupla como argumento
tupla_numeros = (1, 2, 3, 4, 5)
resultado = suma_todos(*tupla_numeros)
print(resultado)  # 15

En este ejemplo, el operador * se utiliza para desempaquetar la tupla y pasar sus elementos como argumentos separados a la función.

Cuándo utilizar tuplas en vez de listas

Las tuplas tienen varias ventajas:

  1. Inmutabilidad: Al ser inmutables, son más seguras para almacenar datos que no deben cambiar, como fechas, coordenadas o claves de diccionarios.
  2. Claves de diccionarios: Las tuplas son «hashables», lo que significa que pueden usarse como claves en diccionarios. Las listas, al ser mutables, no son «hashables» y no se pueden utilizar como claves.
  3. Rendimiento: Las tuplas son ligeramente más rápidas que las listas debido a su inmutabilidad. Si tienes un conjunto de datos que no cambiará, usar tuplas puede ser más eficiente.
  4. Empaquetado y desempaquetado: Las tuplas permiten un empaquetado y desempaquetado sencillo de elementos.
  5. Comparación: Las tuplas se pueden comparar directamente, lo que facilita su uso para ordenar o realizar comparaciones.

Tuplas como claves de diccionarios

Hablaremos de los diccionarios en otra unidad, pero queremos anticipar ahora la justificación del uso de tuplas para acceder a nuestros datos. Como hemos mencionado, a diferencia de las listas, las tuplas se pueden utilizar como claves en diccionarios debido a su inmutabilidad. Por ello, cuando necesitamos una clave compuesta por múltiples elementos, las tuplas son la opción más adecuada:

diccionario = {("Juan", 25): "Estudiante", ("María", 30): "Profesora"}

# Acceder al valor utilizando una tupla como clave
valor = diccionario[("Juan", 25)]  # "Estudiante"

Programación con Python: Listas

Las listas en Python son una estructura de datos muy versátil que permite almacenar y manipular colecciones de elementos. Son secuencias ordenadas y modificables, y pueden contener elementos de diferentes tipos. A continuación mostraremos las principales operaciones que podemos realizar con listas en Python, e incluiremos explicaciones y ejemplos prácticos.

Creación de listas

Podemos crear listas en Python encerrando los elementos entre corchetes []:

# Lista vacía
lista_vacia = []

# Lista de números enteros
numeros_enteros = [1, 2, 3, 4, 5]

# Lista de números flotantes
numeros_flotantes = [1.5, 2.25, 3.75]

# Lista de cadenas de texto
nombres = ["Ana", "Carlos", "María"]

# Lista con elementos de diferentes tipos
mixta = [10, "Python", True, 3.14]

Acceso a elementos

Podemos acceder a los elementos de una lista utilizando índices, teniendo en cuenta que el primer elemento tiene un índice de 0, y el último de -1:

numeros = [10, 20, 30, 40, 50]

primer_elemento = numeros[0]   # 10
segundo_elemento = numeros[1]  # 20
ultimo_elemento = numeros[-1]  # 50 (índice negativo para acceder al último elemento)

Modificación de elementos

Podemos modificar los elementos de una lista asignando nuevos valores a través de sus índices:

nombres = ["Ana", "Carlos", "María"]

nombres[1] = "Juan"  # Modificar el segundo elemento de la lista

print(nombres)  # ["Ana", "Juan", "María"]

Operaciones con listas

Longitud de la lista

Podemos obtener la longitud de una lista utilizando la función len():

numeros = [1, 2, 3, 4, 5]
longitud = len(numeros)  # 5

Concatenación de listas

Podemos concatenar dos o más listas utilizando el operador +:

lista1 = [1, 2, 3]
lista2 = [4, 5, 6]
concatenada = lista1 + lista2  # [1, 2, 3, 4, 5, 6]

Repetición de listas

Podemos repetir una lista utilizando el operador *:

lista = [1, 2, 3]
repetida = lista * 3  # [1, 2, 3, 1, 2, 3, 1, 2, 3]

Añadir elementos a una lista

Podemos añadir elementos a una lista utilizando los métodos append() e insert():

frutas = ["manzana", "plátano"]

# Método append(): añade un elemento al final de la lista
frutas.append("naranja")  # ["manzana", "plátano", "naranja"]

# Método insert(): inserta un elemento en una posición específica de la lista
frutas.insert(1, "pera")  # ["manzana", "pera", "plátano", "naranja"]

Eliminar elementos de una lista

Podemos eliminar elementos de una lista utilizando los métodos remove() y pop(), y también mediante una sentencia del:

nombres = ["Ana", "Carlos", "María"]

# Método remove(): elimina el primer elemento que coincida con el valor proporcionado
nombres.remove("Carlos")  # ["Ana", "María"]

# Método pop(): elimina el elemento en la posición dada (o el último si no se proporciona índice)
nombres.pop(0)  # ["María"]

# Sentencia del: elimina el elemento en la posición dada (o toda la lista si no se proporciona índice)
del nombres[0]  # []

Búsqueda en listas

Podemos buscar elementos en una lista utilizando el operador in:

numeros = [1, 2, 3, 4, 5]

existe_3 = 3 in numeros  # True
existe_6 = 6 in numeros  # False

Comprobar si una lista está vacía

Podemos comprobar si una lista está vacía simplemente usando el valor booleano de la lista. En Python, una lista vacía se evalúa como False, mientras que una lista con elementos se evalúa como True:

lista_vacia = []
lista_no_vacia = [1, 2, 3]

if not lista_vacia:
    print("Esta lista está vacía.")

if lista_no_vacia:
    print("Esta lista contiene elementos.")

Comprobar si un elemento existe en una lista

Podemos utilizar el operador in para comprobar si un elemento está presente en una lista:

numeros = [1, 2, 3, 4, 5]

if 3 in numeros:
    print("El número 3 está en la lista.")

Comparación de listas

Podemos comparar listas para verificar si son iguales o diferentes:

lista1 = [1, 2, 3]
lista2 = [1, 2, 3]
lista3 = [4, 5, 6]

print(lista1 == lista2)  # True (misma estructura y elementos)
print(lista1 == lista3)  # False (elementos diferentes)

Troceado de listas (slicing)

Podemos obtener sublistas (slices) de una lista utilizando la sintaxis [inicio:fin] teniendo en cuenta que el índice de inicio sí está incluido, pero el de fin no:

numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

print(numeros[2:6])  # [3, 4, 5, 6]
print(numeros[2:])   # [3, 4, 5, 6, 7, 8, 9, 10]
print(numeros[:-2])  # [1, 2, 3, 4, 5, 6, 7, 8]

También disponemos de funcionalidades más avanzadas, como el paso o la asignación de valores con la sintaxis [inicio:fin:paso]:

numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Obtener una sublista con paso negativo (se recorre en orden inverso)
sub_lista_inversa = numeros[::-1]  # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

# Obtener una sublista con paso positivo (obtener los números pares)
pares = numeros[1::2]  # [2, 4, 6, 8, 10]

# Modificar valores usando slicing
numeros[1:4] = [20, 30, 40]  # [1, 20, 30, 40, 5, 6, 7, 8, 9, 10]

# Eliminar elementos usando slicing (reemplazar con una lista vacía)
numeros[1:4] = []  # [1, 5, 6, 7, 8, 9, 10]

Listas anidadas

En Python podemos tener listas dentro de listas, lo que se conoce como listas anidadas:

lista_anidada = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

print(lista_anidada[1][2])  # 6 (tercer elemento de la segunda lista)

Copia de listas

Debemos tener en cuenta que al asignar una lista a otra variable, ambas variables apuntan a la misma lista en memoria. Si modificamos una de ellas, la otra también cambiará. Para crear una copia independiente de una lista, podemos utilizar el método copy() o la notación de slicing:

original = [1, 2, 3]

# Copia utilizando copy()
copia1 = original.copy()

# Copia utilizando slicing
copia2 = original[:]

# Modificar la copia independiente
copia1[0] = 100

print(original)  # [1, 2, 3]
print(copia1)    # [100, 2, 3]
print(copia2)    # [1, 2, 3]

Como se puede observar en el ejemplo, la modificación de copia1 no afecta a la lista original, ya que son listas diferentes en memoria. Sin embargo, debemos tener en cuenta que si la lista contiene objetos mutables (como listas anidadas o diccionarios), las copias independientes todavía pueden compartir referencias a esos objetos internos. Por lo tanto, si modificamos un objeto mutable dentro de una lista copiada, ese cambio se reflejará en ambas listas.

Listas y bucles

Las listas son especialmente útiles cuando se combinan con bucles para procesar múltiples elementos de manera eficiente.

Bucle «for» con listas

Este bucle for recorre la lista numeros y muestra cada elemento en la consola:

numeros = [1, 2, 3, 4, 5]

for numero in numeros:
    print(numero)

Bucle «for» con índices y enumeración

A veces resulta útil acceder tanto al índice como al elemento en cada iteración. Podemos usar la función enumerate() para obtener ambos:

frutas = ["manzana", "plátano", "naranja"]

for indice, fruta in enumerate(frutas):
    print(f"Índice: {indice}, Fruta: {fruta}")

Bucle «while» con listas

El bucle while se puede usar para recorrer una lista hasta que se cumpla una condición:

numeros = [1, 2, 3, 4, 5]
indice = 0

while indice < len(numeros):
    print(numeros[indice])
    indice += 1

Comprensión de listas

Las comprensiones de listas nos proporcionan una forma muy concisa y legible para crear listas basadas en una expresión y un bucle for:

# Crear una lista de cuadrados de los números del 1 al 5
cuadrados = [numero ** 2 for numero in range(1, 6)]  # [1, 4, 9, 16, 25]

# Crear una lista solo con números pares del 1 al 10
pares = [numero for numero in range(1, 11) if numero % 2 == 0]  # [2, 4, 6, 8, 10]

También podemos utilizar comprensión avanzada para realizar tareas más complejas:

# Obtener todos los números impares mayores que 10 en una lista
numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
impares_mayores_que_10 = [numero for numero in numeros if numero > 10 and numero % 2 != 0]

# Crear una matriz de ceros de 3x3 utilizando comprensión de listas anidadas
matriz_ceros = [[0 for _ in range(3)] for _ in range(3)]

Funciones y métodos útiles para listas

Python proporciona diversas funciones y métodos que pueden resultar muy útiles para trabajar con listas:

numeros = [3, 1, 5, 2, 4]

# Ordenar la lista de forma ascendente
numeros.sort()  # [1, 2, 3, 4, 5]

# Ordenar la lista de forma descendente
numeros.sort(reverse=True)  # [5, 4, 3, 2, 1]

# Obtener el índice de la primera aparición de un elemento
indice = numeros.index(4)  # 1

# Contar el número de veces que aparece un elemento en la lista
apariciones = numeros.count(3)  # 1

# Obtener una copia ordenada de la lista sin modificar la original
lista_ordenada = sorted(numeros)  # [1, 2, 3, 4, 5]

# Limpiar la lista (eliminar todos los elementos)
numeros.clear()  # []

Función map()

La función map() se puede utilizar para aplicar una función a todos los elementos de una lista y devolver una nueva lista con los resultados:

def cuadrado(numero):
    return numero ** 2

numeros = [1, 2, 3, 4, 5]
cuadrados = list(map(cuadrado, numeros))  # [1, 4, 9, 16, 25]

También podemos utilizar comprensión de listas para lograr el mismo resultado de manera más concisa:

numeros = [1, 2, 3, 4, 5]
cuadrados = [numero ** 2 for numero in numeros]  # [1, 4, 9, 16, 25]

Función filter()

La función filter() se puede utilizar para filtrar elementos de una lista según una condición dada:

def es_par(numero):
    return numero % 2 == 0

numeros = [1, 2, 3, 4, 5, 6]
pares = list(filter(es_par, numeros))  # [2, 4, 6]

Nuevamente, podemos utilizar comprensión de listas para lograr el mismo resultado:

numeros = [1, 2, 3, 4, 5, 6]
pares = [numero for numero in numeros if numero % 2 == 0]  # [2, 4, 6]

Función sum()

La función sum() nos permite sumar todos los elementos de una lista numérica:

numeros = [1, 2, 3, 4, 5]
total = sum(numeros)  # 15

Función join()

La función join() nos permite unir elementos de una lista para formar una cadena de texto:

nombres = ["Ana", "Carlos", "María"]
cadena_unida = ", ".join(nombres)  # "Ana, Carlos, María"

Función zip()

La función zip() combina elementos de dos o más listas en tuplas:

nombres = ["Ana", "Carlos", "María"]
edades = [25, 30, 28]

combinado = list(zip(nombres, edades))
# [('Ana', 25), ('Carlos', 30), ('María', 28)]

Función sorted()

La función sorted() nos permite obtener una nueva lista ordenada a partir de una lista dada sin modificar la original:

numeros = [3, 1, 5, 2, 4]
numeros_ordenados = sorted(numeros)  # [1, 2, 3, 4, 5]

Función reversed()

La función reversed() nos permite obtener una nueva lista con sus elementos en orden inverso sin modificar la original:

numeros = [1, 2, 3, 4, 5]

for numero in reversed(numeros):
    print(numero) # [5, 4, 3, 2, 1]

for numero in numeros:
    print(numero) # [1, 2, 3, 4, 5]

Función enumerate()

La función enumerate() nos permite obtener tanto el índice como el elemento durante la iteración:

frutas = ["manzana", "plátano", "naranja"]

for indice, fruta in enumerate(frutas):
    print(f"Índice: {indice}, Fruta: {fruta}")

Método count()

El método count() nos permite contar cuántas veces aparece un elemento específico en una lista:

numeros = [1, 2, 2, 3, 4, 2]
contador = numeros.count(2)  # 3 (el número 2 aparece 3 veces en la lista)

Método index()

El método index() nos permite encontrar el índice de la primera aparición de un elemento en una lista:

numeros = [10, 20, 30, 40, 50]
indice = numeros.index(30)  # 2 (el número 30 está en el índice 2 de la lista)

Método clear()

El método clear() se utiliza para eliminar todos los elementos de una lista, dejándola vacía:

numeros = [1, 2, 3, 4, 5]
numeros.clear()  # []

Listas como pilas y colas

Podemos usar una lista para implementar una pila (LIFO) o una cola (FIFO):

# Implementación de una pila usando una lista
pila = []
pila.append(1)         # [1]
pila.append(2)         # [1, 2]
elemento = pila.pop()  # elemento = 2, pila = [1]

# Implementación de una cola usando una lista (menos eficiente)
cola = []
cola.append(1)          # [1]
cola.append(2)          # [1, 2]
elemento = cola.pop(0)  # elemento = 1, cola = [2]

Listas y mutabilidad

Las listas son mutables, lo que significa que podemos modificar sus elementos sin crear una nueva lista. Por ejemplo, podemos agregar, eliminar o actualizar elementos en una lista sin tener que crear una copia:

numeros = [1, 2, 3]
numeros[0] = 10  # [10, 2, 3]

numeros.append(4)  # Agregar un elemento al final: [10, 2, 3, 4]
numeros.insert(1, 5)  # Insertar un elemento en una posición: [10, 5, 2, 3, 4]

numeros.remove(2)  # Eliminar el elemento 2: [10, 5, 3, 4]
numeros.pop()  # Eliminar el último elemento: [10, 5, 3]

del numeros[1]  # Eliminar un elemento por índice: [10, 3]

numeros.extend([6, 7, 8])  # Extender la lista con otra: [10, 3, 6, 7, 8]

Como se observa en el ejemplo, podemos modificar los elementos de una lista directamente y realizar varias operaciones para agregar o eliminar elementos según sea necesario.

Clonación de listas

Si queremos crear una copia independiente de una lista, debemos asegurarnos de no hacer una asignación directa, ya que ambas variables apuntarían a la misma lista en memoria. Podemos utilizar el método copy() o la notación de slicing para clonar una lista:

original = [1, 2, 3]

# Clonar usando copy()
copia1 = original.copy()

# Clonar usando slicing
copia2 = original[:]

Ahora, las tres listas son independientes y cualquier modificación en una lista no afectará a las otras.

Conversiones de datos básicos a listas

A continuación veremos cómo realizar conversiones de diferentes tipos de datos básicos (cadenas y enteros por ejemplo) a listas en Python. En general, podremos convertir cualquier secuencia o estructura iterable en una lista utilizando la función list().

Conversión de cadenas de texto a lista

Podemos convertir una cadena de texto en una lista utilizando el método split(). Este método separa la cadena en subcadenas usando un delimitador específico y devuelve una lista con las subcadenas:

cadena = "Hola,esto,es,una,cadena"
lista = cadena.split(",")  # ['Hola', 'esto', 'es', 'una', 'cadena']

El delimitador que hemos utilizado en el ejemplo es la coma (,), pero podemos usar cualquier carácter como delimitador:

otra_cadena = "Esto-es-una-cadena-con-guiones"
otra_lista = otra_cadena.split("-")  # ['Esto', 'es', 'una', 'cadena', 'con', 'guiones']

Si no especificamos un delimitador en split(), se utilizará el espacio en blanco como delimitador por defecto:

texto = "Hola esto es una cadena"
palabras = texto.split()  # ['Hola', 'esto', 'es', 'una', 'cadena']

Conversión de caracteres de una cadena a lista

Si tenemos una cadena de texto y queremos utilizar cada carácter para formar una lista, podemos hacerlo utilizando la función list() o también con una comprensión de listas. En el siguiente ejemplo, iteramos por cada carácter en la cadena y creamos una lista con cada carácter como elemento:

cadena = "Hola"
lista1 = list(cadena)  # ['H', 'o', 'l', 'a']
lista2 = [caracter for caracter in cadena]  # ['H', 'o', 'l', 'a']

Conversión de valores numéricos a lista

Si queremos convertir un valor numérico en una lista, podemos hacerlo utilizando la función list() pasando el valor como un argumento iterable. En el siguiente ejemplo convertimos el número en una cadena de texto utilizando str(), y luego utilizamos list() para formar una lista con todos los dígitos:

numero = 12345
lista = list(str(numero))  # ['1', '2', '3', '4', '5']

Conversión de rangos a lista

Los rangos en Python también se pueden convertir a listas utilizando la función list(). Por ejemplo, podemos crear un rango del 1 al 5 y luego convertirlo en una lista:

rango = range(1, 6)
lista = list(rango)  # [1, 2, 3, 4, 5]

Listas, funciones y conjuntos

A continuación enumeramos algunas ventajas adicionales asociadas al uso de funciones y otros tipos de estructuras de datos que veremos de forma detallada en otras unidades. Hemos creído conveniente exponerlas ahora para ser conscientes del gran potencial que presentan las listas de Python.

Listas como argumentos de funciones

Las listas se pueden utilizar como argumentos de funciones, lo que nos proporciona la funcionalidad necesaria para pasar múltiples elementos a una función agrupándolos en una sola variable. Además, esto nos permitirá por ejemplo realizar cambios en los elementos de la lista dentro de la función:

def duplicar_elementos(lista):
    for i in range(len(lista)):
        lista[i] *= 2

numeros = [1, 2, 3, 4, 5]
duplicar_elementos(numeros)

print(numeros)  # [2, 4, 6, 8, 10]

Listas y funciones lambda

Las funciones lambda son funciones anónimas que se pueden usar en combinación con las funciones map(), filter(), y otras:

numeros = [1, 2, 3, 4, 5]

# Elevar al cuadrado cada número usando una función lambda con map()
cuadrados = list(map(lambda x: x ** 2, numeros))  # [1, 4, 9, 16, 25]

# Filtrar solo los números pares usando una función lambda con filter()
pares = list(filter(lambda x: x % 2 == 0, numeros))  # [2, 4]

Listas y operaciones con conjuntos

Podemos realizar operaciones de conjuntos (unión, intersección, diferencia) con listas utilizando el tipo de dato set:

lista1 = [1, 2, 3]
lista2 = [3, 4, 5]

# Unión de listas
union = list(set(lista1) | set(lista2))  # [1, 2, 3, 4, 5]

# Intersección de listas
interseccion = list(set(lista1) & set(lista2))  # [3]

# Diferencia entre listas (elementos que están en lista1 pero no en lista2)
diferencia = list(set(lista1) - set(lista2))  # [1, 2]

Debemos matizar que el tipo de dato set no mantiene el orden original de los elementos, por lo que al convertirlo de vuelta a una lista, el orden puede variar.

Programación con Python: Bucles

Los bucles son estructuras de control que nos permiten repetir un bloque de código varias veces o recorrer elementos en una secuencia. En Python disponemos del bucle for y el bucle while. A continuación mostraremos cómo utilizarlos con ejemplos para comprender mejor su funcionamiento.

Bucle «for»

El bucle for se utiliza para iterar sobre secuencias de datos tales como cadenas, listas, tuplas, o diccionarios (estos tres últimos tipos de datos se explican con más detalle en otra unidad).

En el siguiente ejemplo, el bucle for recorre la cadena mensaje y muestra en la consola cada uno de sus caracteres:

# Ejemplo con una cadena
mensaje = "Hola, Python!"
for caracter in mensaje:
    print(caracter)

En el siguiente ejemplo empleamos un bucle for para recorrer la lista frutas y mostrar cada uno de sus elementos:

# Ejemplo con una lista
frutas = ["manzana", "plátano", "naranja"]
for fruta in frutas:
    print(fruta)

A continuación mostramos un bucle for que recorre cada par clave-valor del diccionario estudiantes y muestra el nombre y la edad de cada estudiante:

# Ejemplo con un diccionario
estudiantes = {"Juan": 18, "María": 20, "Carlos": 22}
for nombre, edad in estudiantes.items():
    print(nombre, "tiene", edad, "años.")

Bucle «while»

El bucle while se utiliza para repetir un bloque de código mientras una condición sea verdadera. En el siguiente ejemplo, el bucle while muestra el valor del contador mientras sea menor o igual a 5:

contador = 1
while contador <= 5:
    print("Contador:", contador)
    contador += 1

Sentencias de control en bucles

Dentro de los bucles podemos utilizar las sentencias break, continue y else para controlar el flujo de ejecución.

break

Permite salir del bucle de manera prematura si se cumple una condición. En el siguiente ejemplo, el bucle for imprimirá los números del 1 al 4 y luego se detendrá cuando llegue a 5:

for numero in range(1, 11):
    if numero == 5:
        break
    print(numero)

continue

Permite saltar a la siguiente iteración del bucle si se cumple una condición. En el siguiente ejemplo, el bucle for imprimirá solo los números impares del 1 al 10, saltando los números pares:

for numero in range(1, 11):
    if numero % 2 == 0:
        continue
    print(numero)

else

Se ejecuta cuando el bucle se completa sin encontrar una sentencia break. Por ejemplo, el siguiente bucle for imprimirá los números del 1 al 5 y luego el programa mostrará «Fin del bucle»:

for numero in range(1, 6):
    print(numero)
else:
    print("Fin del bucle")

Bucles anidados

Podemos incluir bucles dentro de bucles, lo que se conoce como bucles anidados. También podemos utilizar break y continue para controlar el flujo de ejecución dentro de ellos. Por ejemplo, los siguientes bucles for anidados imprimirán todos los pares (i, j) del 1 al 3, excepto cuando i sea igual a 2 y j sea igual a 2. En este último caso, el break provocará la salida del bucle interno, continuando con la siguiente iteración del bucle externo:

for i in range(1, 4):
    for j in range(1, 4):
        if i == 2 and j == 2:
            break
        print(i, j)

Bucles infinitos

Es importante tener cuidado con los bucles infinitos, ya que pueden llegar a ejecutar el código que contengan de forma indefinida si no incluimos correctamente una condición que los detenga. Pueden provocar que el programa se bloquee o entre en un estado no deseado. Por ejemplo, el siguiente bucle while se ejecutará de forma indefinida, imprimiendo «Este es un bucle infinito» una y otra vez:

# Bucle infinito con while
while True:
    print("Este es un bucle infinito")

Programación con Python: Condicionales

Los condicionales son una parte fundamental de la programación que nos permite controlar el flujo de ejecución de un programa. En Python se utilizan principalmente tres tipos de condicionales: if, elif (opcional) y else. A continuación mostraremos cómo utilizarlos con ejemplos para comprender mejor su funcionamiento.

Condicionales «if»

El condicional if se utiliza para ejecutar un bloque de código solo si una condición es verdadera. En el siguiente ejemplo, si la variable edad es mayor o igual a 18, se imprimirá «Eres mayor de edad.»:

edad = 18

if edad >= 18:
    print("Eres mayor de edad.")

Condicionales «if» y «else»

El condicional else se utiliza para ejecutar un bloque de código cuando la condición del if es falsa. En el siguiente ejemplo, si la variable edad es mayor o igual a 18, se imprimirá «Eres mayor de edad.», y en caso contrario, se imprimirá «Eres menor de edad.»:

edad = 15

if edad >= 18:
    print("Eres mayor de edad.")
else:
    print("Eres menor de edad.")

Condicionales «if», «elif» y «else»

El condicional elif (abreviatura de «else if») se utiliza para evaluar múltiples condiciones. Se verifica solo si la condición del if anterior es falsa. En el siguiente ejemplo, el programa evalúa la variable calificacion y muestra diferentes mensajes dependiendo del rango en el que se encuentre:

calificacion = 85

if calificacion >= 90:
    print("Tienes una A.")
elif calificacion >= 80:
    print("Tienes una B.")
elif calificacion >= 70:
    print("Tienes una C.")
else:
    print("Tienes una calificación inferior a C.")

Uso de operadores lógicos en condicionales

Podemos combinar múltiples condiciones utilizando los operadores lógicos and (y), or (o) y not (no). En el siguiente ejemplo se evalúa tanto la temperatura como si es un día soleado o no, utilizando el operador and. Si ambas condiciones son verdaderas, se imprimirá «Hace calor y es un día soleado.» Si al menos una de las condiciones es verdadera (usando el operador or), se imprimirá «Hace calor o es un día soleado.» De lo contrario, se imprimirá «No hace calor y no es un día soleado.»:

temperatura = 25
dia_soleado = True

if temperatura > 30 and dia_soleado:
    print("Hace calor y es un día soleado.")
elif temperatura > 30 or dia_soleado:
    print("Hace calor o es un día soleado.")
else:
    print("No hace calor y no es un día soleado.")

Condicionales anidados

Se pueden anidar condicionales dentro de otros condicionales para manejar situaciones más complejas. En el siguiente ejemplo, se verifica primero si la persona es mayor o igual a 18 años. Si es así, se verifica si tiene carnet de conducir para determinar si puede conducir o no:

edad = 25
carnet_conducir = True

if edad >= 18:
    if carnet_conducir:
        print("Puedes conducir.")
    else:
        print("Eres mayor de edad, pero no puedes conducir.")
else:
    print("Eres menor de edad.")

Sentencia match-case

Antes de Python 3.10, las comparaciones múltiples se realizaban utilizando la estructura if-elif-else, lo que podía llevar a una sintaxis un tanto repetitiva y menos legible en ciertos casos. El nuevo match case resuelve este problema ya que permite realizar comparaciones más elegantes y fáciles de leer.

Sintaxis básica

La sintaxis del match case se asemeja a una declaración switch en otros lenguajes de programación. Su forma básica es la siguiente:

match valor:
    case patron1:
        # código a ejecutar si el valor coincide con patron1
    case patron2:
        # código a ejecutar si el valor coincide con patron2
    ...
    case patronN:
        # código a ejecutar si el valor coincide con patronN
    case _:
        # código a ejecutar si no se cumple ninguno de los patrones anteriores

Un ejemplo muy sencillo

En su forma más sencilla, el match case permite comprobar coincidencias con valores específicos de cualquier tipo (números, cadenas, etc). Por ejemplo, utilizando el código del siguiente ejemplo podemos determinar el estado civil de una persona basándonos en el valor de la variable codigo:

match codigo:
    case "S":
        print("Soltero/a")
    case "C":
        print("Casado/a")
    case "D":
        print("Divorciado/a")
    case "V":
        print("Viudo/a")
    case _:
        print("Código inválido")

Equivalencia entre «if-elif-else» y «match-case»

Supongamos que queremos determinar el día de la semana correspondiente a un número del 1 al 7, donde 1 representa el lunes y 7 representa el domingo.

Usando if-elif-else:

if numero == 1:
    print("Lunes")
elif numero == 2:
    print("Martes")
elif numero == 3:
    print("Miércoles")
elif numero == 4:
    print("Jueves")
elif numero == 5:
    print("Viernes")
elif numero == 6:
    print("Sábado")
elif numero == 7:
    print("Domingo")
else:
    print("Número inválido")

Usando match case:

match numero:
    case 1:
        print("Lunes")
    case 2:
        print("Martes")
    case 3:
        print("Miércoles")
    case 4:
        print("Jueves")
    case 5:
        print("Viernes")
    case 6:
        print("Sábado")
    case 7:
        print("Domingo")
    case _:
        print("Número inválido")

Como se puede apreciar, el uso del match case reduce significativamente la cantidad de consultas que se realizan para comprobar el valor de la variable numero y hace que el código resultante sea más fácil de leer.

Combinación de patrones

El match case también permite combinar múltiples patrones utilizando la sintaxis case patron1 | patron2 | ...:. En el siguiente ejemplo agrupamos diversos valores de una nota numérica con el propósito de mostrar el texto descriptivo de la calificación que se haya obtenido:

match nota:
    case 0 | 1 | 2 | 3 | 4:
        print("Suspendido")
    case 5 | 6:
        print("Aprobado")
    case 7 | 8:
        print("Notable")
    case 9 | 10:
        print("Sobresaliente")
    case _:
        print("Nota no válida")

Además Python nos permite comprobar coincidencias con datos de cualquier tipo (cadenas, listas, tuplas, diccionarios, etc). Vamos a ver un ejemplo en el que tenemos una lista de alimentos representados por cadenas de texto. Utilizamos el match case para clasificar cada alimento en diferentes categorías: «Frutas», «Verduras», «Proteínas» o «Carbohidratos». Si el alimento no coincide con ninguna de estas categorías, lo clasificamos como «Desconocido». De esta forma, el match case nos permitirá clasificar rápidamente cada alimento en su respectiva categoría sin tener que escribir múltiples sentencias if-elif-else, y por lo tanto obtenemos un código más simple y fácil de entender:

match alimento:
    case "manzana" | "pera" | "plátano" | "uva":
        print("Frutas")
    case "zanahoria" | "tomate" | "espinaca" | "lechuga":
        print("Verduras")
    case "pollo" | "pescado" | "res" | "cerdo":
        print("Proteínas")
    case "arroz" | "pasta" | "pan" | "patata":
        print("Carbohidratos")
    case _:
        print("Desconocido")

Consideraciones adicionales

Es importante tener en cuenta que el match case es una característica introducida en Python 3.10, por lo que si estamos utilizando una versión anterior, esta funcionalidad no estará disponible. Además, es recomendable utilizar el match case sólo cuando el código resulte más legible o apropiado para el problema en cuestión. En muchos casos, la estructura if-elif-else tradicional puede ser resultar más adecuada por motivos de compatibilidad o en caso de que podamos resolver nuestro problema utilizando expresiones booleanas sencillas.

Programación con Python: Conversiones entre datos básicos

En Python se pueden convertir datos de un tipo a otro utilizando funciones integradas o métodos específicos para cada tipo de dato. Estas conversiones son útiles cuando necesitamos operar con diferentes tipos de datos o cuando queremos mostrar información en un formato específico. A continuación detallaremos las conversiones más comunes en Python, y proporcionaremos ejemplos prácticos para cada caso.

Conversión a enteros (int)

Podemos convertir datos a enteros utilizando la función int():

# Convertir un número decimal a entero
decimal = 5.75
entero = int(decimal)  # 5 (se descarta la parte decimal)

# Convertir una cadena numérica a entero
cadena_numero = "123"
entero_desde_cadena = int(cadena_numero)  # 123

Conversión a flotantes (float)

Podemos convertir datos a números flotantes utilizando la función float():

# Convertir un entero a número flotante
entero = 10
flotante_desde_entero = float(entero)  # 10.0

# Convertir una cadena numérica a número flotante
cadena_numero = "3.14"
flotante_desde_cadena = float(cadena_numero)  # 3.14

Conversión a cadenas (str)

Podemos convertir datos a cadenas utilizando la función str():

# Convertir un número entero a cadena
entero = 42
cadena_desde_entero = str(entero)  # "42"

# Convertir un número flotante a cadena
flotante = 3.14
cadena_desde_flotante = str(flotante)  # "3.14"

Conversión a booleanos (bool)

Podemos convertir datos a booleanos utilizando la función bool(). En general, los siguientes valores se evaluarán como False en Python, y todo lo demás se evaluará como True:

  • Cualquier número que sea 0 (entero o flotante).
  • Cadenas vacías.
  • Listas, tuplas, diccionarios o conjuntos vacíos.
  • El valor especial None.
# Convertir un número entero a booleano
entero = 10
booleano_desde_entero = bool(entero)  # True

# Convertir un número flotante a booleano
flotante = 0.0
booleano_desde_flotante = bool(flotante)  # False

# Convertir una cadena a booleano
cadena_vacia = ""
booleano_desde_cadena = bool(cadena_vacia)  # False

# Convertir una lista vacía a booleano
lista_vacia = []
booleano_desde_lista = bool(lista_vacia)  # False

# Convertir un valor None a booleano
valor_nulo = None
booleano_desde_nulo = bool(valor_nulo)  # False

Conversión a otras bases o representaciones

En Python también podemos convertir datos a representaciones en formato binario, octal o hexadecimal utilizando las funciones bin(), oct() y hex():

numero = 42

# Convertir a binario
binario = bin(numero)  # '0b101010'

# Convertir a octal
octal = oct(numero)    # '0o52'

# Convertir a hexadecimal
hexadecimal = hex(numero)  # '0x2a'

Es importante tener en cuenta que no todos los tipos de datos se pueden convertir a todas las representaciones. Por ejemplo, no podemos convertir una cadena a binario directamente.

Programación con Python: Cadenas de texto

Las cadenas de texto (también conocidas como strings) son secuencias de caracteres encerradas entre comillas simples o comillas dobles, y nos permiten almacenar y manipular texto en los programas. En Python, las cadenas son objetos inmutables, lo que significa que no se pueden modificar una vez creadas, pero podemos crear nuevas cadenas a partir de ellas con diferentes manipulaciones. Vamos a detallar a continuación la sintaxis básica relacionada con las cadenas, e incluiremos ejemplos prácticos.

Creación de cadenas

Podemos crear una cadena asignando un valor entre comillas (simples o dobles) a una variable:

mensaje = "Hola, Python!"
nombre = 'María'
direccion = "Calle San José, 123"

También podemos utilizar triples comillas (simples o dobles) para crear cadenas de varias líneas:

parrafo = """Este es un ejemplo
de una cadena con varias líneas.
Puedes usar triples comillas para ello."""

Operaciones con cadenas

Longitud de una cadena

Podemos obtener la longitud de una cadena utilizando la función len():

mensaje = "Hola, Python!"
longitud = len(mensaje)  # 13 (incluyendo espacios y signos de puntuación)

Concatenación

Podemos unir cadenas utilizando el operador +:

saludo = "Hola, "
nombre = "María"
mensaje_completo = saludo + nombre  # "Hola, María"

Repetición

Podemos repetir una cadena utilizando el operador *:

cadena = "abc"
repetida = cadena * 3  # "abcabcabc"

Indexación y segmentación

Las cadenas son secuencias de caracteres, lo que significa que podemos acceder a caracteres individuales utilizando índices y también podemos segmentar la cadena para obtener subcadenas:

texto = "Python es genial"

primer_caracter = texto[0]  # "P" (el primer carácter tiene índice 0)
ultimo_caracter = texto[-1]  # "l" (el último carácter tiene índice -1)

segmento = texto[7:9]  # "es" (segmento desde el índice 7 hasta el índice 8, no incluye el índice 9)

# También puedes omitir el índice de inicio o de fin para segmentar desde el principio o hasta el final, respectivamente.
inicio_omitiendo = texto[:6]  # "Python"
fin_omitiendo = texto[10:]   # "genial"

Búsqueda en cadenas

Podemos buscar subcadenas dentro de una cadena utilizando los métodos find() e index():

texto = "Python es un lenguaje de programación"
posicion_find = texto.find("lenguaje")  # 13 (posición de la primera ocurrencia)
posicion_index = texto.index("lenguaje")  # 13 (posición de la primera ocurrencia)

# Si la subcadena no se encuentra, find() devuelve -1, mientras que index() genera una excepción ValueError.
posicion_find_no_encontrada = texto.find("Java")  # -1
posicion_index_no_encontrada = texto.index("Java")  # ValueError: substring not found

Reemplazo y formato

Podemos reemplazar subcadenas en una cadena utilizando el método replace():

mensaje = "Hola, NAME!"
nuevo_mensaje = mensaje.replace("NAME", "María")  # "Hola, María!"

También podemos utilizar el método format() para que la cadena incluya los valores de diferentes variables:

nombre = "Juan"
edad = 30
saludo = "Hola, mi nombre es {} y tengo {} años.".format(nombre, edad)
# "Hola, mi nombre es Juan y tengo 30 años."

Caracteres especiales

Python admite varios caracteres especiales que se pueden incluir en las cadenas, como por ejemplo:

  • \n: Nueva línea.
  • \t: Tabulación.
  • \': Comilla simple.
  • \": Comilla doble.
  • \\: Barra invertida.
mensaje_multilinea = "Hola,\nPython!"
print(mensaje_multilinea)
# Salida:
# Hola,
# Python!

mensaje_tabs = "Hola,\tPython!"
print(mensaje_tabs)
# Salida: Hola,    Python!

mensaje_comillas = "Ella dijo: \"Hola, Python!\""
print(mensaje_comillas)
# Salida: Ella dijo: "Hola, Python!"

Métodos útiles para cadenas

Python incluye varios métodos para trabajar con cadenas. Algunos de los más útiles son:

texto = "Python es un lenguaje de programación"

# Convertir a mayúsculas y minúsculas
texto_mayusculas = texto.upper()  # "PYTHON ES UN LENGUAJE DE PROGRAMACIÓN"
texto_minusculas = texto.lower()  # "python es un lenguaje de programación"

# Capitalizar la primera letra de la cadena
texto_capitalizado = texto.capitalize()  # "Python es un lenguaje de programación"

# Contar ocurrencias de una subcadena
ocurrencias = texto.count("a")  # 3 (número de veces que aparece "a" en la cadena)

# Verificar si una cadena comienza o termina con una subcadena
comienza_con = texto.startswith("Python")  # True
termina_con = texto.endswith("programación")  # True

# Separar una cadena en una lista de subcadenas por un carácter específico
palabras = texto.split(" ")  # ['Python', 'es', 'un', 'lenguaje', 'de', 'programación']

# Eliminar espacios en blanco al principio y al final de la cadena
texto_limpio = "   Hola, Python!   "
texto_sin_espacios = texto_limpio.strip()  # "Hola, Python!"

F-strings

Las f-strings (o cadenas formateadas) nos proporcionan una forma muy legible para construir cadenas en Python (están disponibles a partir de la versión 3.6). Las f-strings nos permiten incorporar expresiones dentro de las cadenas, lo que facilita la inclusión de variables y otros valores en ellas sin tener que utilizar métodos de formato o concatenación. Para usar f-strings, simplemente debemos colocar una «f» o «F» antes del inicio de la cadena y luego añadimos las expresiones utilizando llaves {} dentro de la cadena:

nombre = "Juan"
edad = 30

# Usando f-string para formatear la cadena
mensaje = f"Hola, mi nombre es {nombre} y tengo {edad} años."
print(mensaje)
# Salida: "Hola, mi nombre es Juan y tengo 30 años."

Las expresiones dentro de las llaves serán evaluadas y su valor se incluirá en la cadena final. Se puede incluir cualquier tipo de expresión válida dentro de las llaves, como operaciones matemáticas, llamadas a funciones, y más:

a = 10
b = 5

# Operaciones matemáticas dentro de una f-string
resultado = f"La suma de {a} y {b} es {a + b}, y el producto es {a * b}."
print(resultado)
# Salida: "La suma de 10 y 5 es 15, y el producto es 50."

También se puede aplicar formato a las expresiones dentro de las llaves. Por ejemplo, podemos especificar la cantidad de decimales para un número flotante o el ancho para un número entero:

precio = 9.99

# Formato de número flotante dentro de una f-string
mensaje_precio = f"El precio es: ${precio:.2f}"
print(mensaje_precio)
# Salida: "El precio es: $9.99"

cantidad = 100

# Formato de número entero dentro de una f-string
mensaje_cantidad = f"La cantidad es: {cantidad:05d}"
print(mensaje_cantidad)
# Salida: "La cantidad es: 00100"

En el ejemplo anterior, :.2f indica que queremos mostrar el número flotante con dos decimales, mientras que :05d indica que queremos que el número entero tenga un ancho de 5 dígitos, rellenando con ceros a la izquierda si es necesario.

Programación con Python: Operadores

Los operadores en Python son símbolos especiales que se emplean para realizar diferentes acciones y cálculos utilizando variables y valores. Estas operaciones pueden ser matemáticas, de comparación, lógicas, de asignación, etc. Los operadores son fundamentales en la programación, ya que nos permiten realizar cálculos, tomar decisiones y manipular datos de manera eficiente.

Operadores Aritméticos

Los operadores aritméticos se utilizan para realizar operaciones matemáticas en números. Aquí están los principales operadores aritméticos en Python:

  • Suma (+): Suma dos valores.
  • Resta (-): Resta el segundo valor del primero.
  • Multiplicación (*): Multiplica dos valores.
  • División (/): Divide el primer valor por el segundo. Siempre devuelve un flotante.
  • División entera (//): Divide el primer valor por el segundo y redondea el resultado hacia abajo al entero más cercano.
  • Módulo (%): Devuelve el resto de la división entera entre el primer valor y el segundo.
  • Potencia (**): Eleva el primer valor a la potencia del segundo.
a = 10
b = 3

suma = a + b          # 13
resta = a - b         # 7
producto = a * b      # 30
division = a / b      # 3.3333333333333335
division_entera = a // b  # 3
resto = a % b         # 1
potencia = a ** b     # 1000

Operadores de Comparación

Los operadores de comparación se utilizan para comparar dos valores y devuelven un valor booleano (True o False). Aquí están los principales operadores de comparación en Python:

  • Igual que (==): Comprueba si los valores son iguales.
  • Diferente que (!=): Comprueba si los valores son diferentes.
  • Mayor que (>): Comprueba si el primer valor es mayor que el segundo.
  • Menor que (<): Comprueba si el primer valor es menor que el segundo.
  • Mayor o igual que (>=): Comprueba si el primer valor es mayor o igual que el segundo.
  • Menor o igual que (<=): Comprueba si el primer valor es menor o igual que el segundo.
x = 10
y = 5

igual_que = x == y               # False
diferente_que = x != y           # True
mayor_que = x > y                # True
menor_que = x < y                # False
mayor_o_igual_que = x >= y       # True
menor_o_igual_que = x <= y       # False

Operadores Lógicos

Los operadores lógicos se utilizan para combinar expresiones booleanas y devuelven un valor booleano. Aquí están los principales operadores lógicos en Python:

  • and (y): Devuelve True si ambas expresiones son verdaderas.
  • or (o): Devuelve True si al menos una de las expresiones es verdadera.
  • not (no): Devuelve el valor opuesto de la expresión.
a = True
b = False

resultado_and = a and b         # False
resultado_or = a or b           # True
resultado_not_a = not a         # False
resultado_not_b = not b         # True

Operadores de Pertenencia

Los operadores de pertenencia se utilizan para comprobar si un valor está presente en una secuencia, como una lista, tupla o cadena.

  • in: Devuelve True si el valor está presente en la secuencia.
  • not in: Devuelve True si el valor no está presente en la secuencia.
mi_lista = [1, 2, 3, 4, 5]

esta_en_lista = 3 in mi_lista         # True
no_esta_en_lista = 6 not in mi_lista  # True

mi_cadena = "Hola, Python!"

esta_en_cadena = "Python" in mi_cadena          # True
no_esta_en_cadena = "Java" not in mi_cadena     # True

Operadores de Identidad

Los operadores de identidad se utilizan para comparar si dos variables se refieren al mismo objeto en memoria.

  • is: Devuelve True si ambas variables apuntan al mismo objeto.
  • is not: Devuelve True si ambas variables no apuntan al mismo objeto.
a = [1, 2, 3]
b = a  # b apunta a la misma lista en memoria que a

es_mismo_objeto = a is b         # True

c = [1, 2, 3]

es_distinto_objeto = a is not c  # True

Operadores de Asignación

Los operadores de asignación se utilizan para asignar valores a variables.

  • = : Asignación básica.
  • += : Asignación con suma.
  • -= : Asignación con resta.
  • *= : Asignación con multiplicación.
  • /= : Asignación con división.
a = 10

a = 5   # Ahora a tiene el valor de 5
a += 2  # Ahora a tiene el valor de 7
a -= 3  # Ahora a tiene el valor de 4
a *= 2  # Ahora a tiene el valor de 8
a /= 4  # Ahora a tiene el valor de 2.0

Operador Ternario

El operador ternario nos permite escribir una expresión condicional de una forma muy concisa:

edad = 18

es_mayor_edad = True if edad >= 18 else False

En este caso, es_mayor_edad será True si la edad es mayor o igual a 18, y False en caso contrario.