Interacción Básica con Python y el Entorno de Desarrollo
Python es un lenguaje versátil que permite interactura de diversas maneras, desde la ejecución de scripts hasta la consola interactiva. Comprender cómo iniciar y salir del intérprete, así como manejar argumentos de línea de comandos y funciones de utilidad, es fundamental para cualquier desarrollador.
Consola Interactiva de Python
Para iniciar el intérprete interactivo de Python desde la terminal de su sistema (por ejemplo, Ubuntu o cualquier otro sistema operativo), simplemente escriba python3 (o python si esa es la versión predeterminada).
$ python3
Python 3.x.x (default, ...)
[GCC ...] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
Para salir del intérprete, puede usar la función quit() o presionar Ctrl+D (en sistemas Unix/Linux) o Ctrl+Z seguido de Enter (en Windows).
>>> quit()
$
Ejecución de Scripts de Python
Los scripts de Python se ejecutan pasando el nombre del archivo al intérprete:
$ python3 mi_script.py
Argumentos de Línea de Comandos (sys.argv)
El módulo sys proporciona acceso a variables y funciones que interactúan fuertemente con el intérprete. Una de sus utilidades es sys.argv, una lista de cadenas que contiene los argumentos de línea de comandos pasados a un script de Python. El primer elemento de sys.argv es siempre el nombre del script.
Considere un script llamado procesar_argumentos.py:
# procesar_argumentos.py
import sys
print(f"Nombre del script: {sys.argv[0]}")
print(f"Número total de argumentos (incluyendo el script): {len(sys.argv)}")
print("Argumentos pasados:")
for i, arg in enumerate(sys.argv[1:]):
print(f" Argumento {i+1}: {arg}")
if __name__ == '__main__':
# Este bloque solo se ejecuta cuando el script se ejecuta directamente
print("\nEste mensaje aparece solo al ejecutar el script directamente.")
Ejecución desde la terminal:
$ python3 procesar_argumentos.py primer_valor segundo_valor 42
Salida esperada:
Nombre del script: procesar_argumentos.py
Número total de argumentos (incluyendo el script): 4
Argumentos pasados:
Argumento 1: primer_valor
Argumento 2: segundo_valor
Argumento 3: 42
Este mensaje aparece solo al ejecutar el script directamente.
El Bloque if __name__ == '__main__':
Este bloque es una convención común en Python. El intérprete de Python asigna el valor "__main__" a la variable especial __name__ cuando el script se ejecuta directamente. Si el script se importa como un módulo en otro script, __name__ contendrá el nombre del módulo. Esto permite que un archivo Python sirva tanto como un script ejecutable como una biblioteca importable.
Funciones de Utilidad
help(): Permite obtener ayuda sobre objetos, módulos, funciones o tipos. Puede usarlo dentro del intérprete (help(print)) o desde la terminal (pydoc3 print).type(): Retorna el tipo de un objeto o permite crear un nuevo tipo. Por ejemplo,type("Hola")devolverá<class 'str'>.os.path.exists(ruta): Del móduloos.path, verifica si una ruta de archivo o directorio existe. RetornaTrueoFalse.range(): Genera una secuencia de números. Es importante recordar querange(inicio, fin)es un rango semiabierto[inicio, fin), excluyendo el valor final.
Manejo de Entrada y Salida
La interacción con el usuario y la presentación de información son pilares en cualquier aplicación. Python 3 ofrece herramientas robustas para estas tareas.
Salida: La Función print()
La función print() se utiliza para mostrar datos en la consola. En Python 3, print es una función y requiere paréntesis.
Impresión Básica
print("¡Hola, Python!")
Concatenación de Cadenas
Puede unir cadenas usando el operador +:
nombre = "Mundo"
print("Hola, " + nombre + "!")
Formato de Salida
Python 3 ofrece varias formas de formatear cadenas de salida, siendo los f-strings (cadenas literales formateadas) la forma más moderna y recomendada.
F-strings (Python 3.6+)
edad = 30
altura_cm = 175.5
print(f"Mi edad es {edad} años y mi altura es {altura_cm:.1f} cm.")
Método .format()
producto = "manzana"
precio = 1.25
print("El precio de la {} es {:.2f} €.".format(producto, precio))
Marcadores de Posición (Estilo C, compatible pero menos moderno)
ciudad = "Madrid"
temperatura = 25
print("La temperatura en %s es %d grados." % (ciudad, temperatura))
Caracteres Especiales
\n: Salto de línea.\t: Tabulación.
print("Línea 1\nLínea 2\t(Tabulado)")
Entrada: La Función input()
La función input() se utiliza para obtener entrada del usuario desde la consola. Siempre devuelve la entrada como una cadena de texto.
nombre_usuario = input("Por favor, introduce tu nombre: ")
print(f"¡Hola, {nombre_usuario}!")
# Para usar la entrada como número, es necesario convertirla
edad_str = input("¿Cuántos años tienes? ")
try:
edad_int = int(edad_str)
print(f"Confirmado: tienes {edad_int} años.")
except ValueError:
print("Entrada inválida. Por favor, introduce un número.")
Trabajo con Archivos
El manejo de archivos es crucial para la persistencia de datos. Python ofrece una interfaz sencilla para leer y escribir en archivos.
Apertura y Cierre de Archivos
La forma más segura de trabajar con archivos es utilizando la declaración with open(). Esto garantiza que el archivo se cierre automáticamente, incluso si ocurren errores.
Modos de Apertura
'r': Modo de lectura (predeterminado). El archivo debe existir.'w': Modo de escritura. Trunca el archivo si existe; lo crea si no.'a': Modo de adición. Escribe al final del archivo; lo crea si no.'x': Modo de creación exclusiva. Falla si el archivo ya existe.'b': Modo binario (para archivos no textuales como imágenes). Se usa junto con otros modos, ej.'rb','wb'.'+': Modo de actualización (lectura y escritura). Se usa junto con otros modos, ej.'r+','w+'.
# Ejemplo de escritura con 'w'
with open('ejemplo.txt', 'w', encoding='utf-8') as archivo:
archivo.write("Esta es la primera línea.\n")
archivo.write("Esta es la segunda línea.\n")
# Ejemplo de adición con 'a'
with open('ejemplo.txt', 'a', encoding='utf-8') as archivo:
archivo.write("Esta es una nueva línea añadida.\n")
Lectura de Archivos
read(): Leer todo el contenido
Lee el archivo completo como una sola cadena de texto. Se puede pasar un argumento opcional para leer un número específico de caracteres/bytes.
with open('ejemplo.txt', 'r', encoding='utf-8') as archivo:
contenido = archivo.read()
print("--- Contenido completo ---")
print(contenido)
readline(): Leer línea por línea
Lee una sola línea del archivo. Las llamadas sucesivas a readline() leerán las siguientes líneas.
with open('ejemplo.txt', 'r', encoding='utf-8') as archivo:
print("--- Línea por línea con readline() ---")
linea1 = archivo.readline()
linea2 = archivo.readline()
print(f"1: {linea1.strip()}") # .strip() para quitar el salto de línea al final
print(f"2: {linea2.strip()}")
readlines(): Leer todas las líneas en una lista
Lee todas las líneas del archivo y las devuelve como una lista de cadenas, donde cada cadena es una línea del archivo (incluyendo el carácter de nueva línea).
with open('ejemplo.txt', 'r', encoding='utf-8') as archivo:
lineas = archivo.readlines()
print("--- Todas las líneas en una lista con readlines() ---")
for i, linea in enumerate(lineas):
print(f"Línea {i+1}: {linea.strip()}")
Escritura en Archivos
write(cadena): Escribir una cadena
Escribe la cadena proporcionada en el archivo. No añade automáticamente un salto de línea.
# Sobrescribir (o crear) un archivo y escribir varias líneas
with open('nuevo_archivo.txt', 'w', encoding='utf-8') as archivo:
archivo.write("Primera línea escrita.\n")
archivo.write("Segunda línea escrita.\n")
archivo.write("Tercera línea escrita.\n")
print("Archivo 'nuevo_archivo.txt' creado y escrito.")
Posicionamiento en Archivos: seek() y tell()
El "puntero" del archivo indica la posición actual para la lectura o escritura.
tell(): Retorna la posición actual del puntero en el archivo (desplazamiento en bytes desde el inicio).seek(offset, whence=0): Mueve el puntero del archivo a una nueva posición.offset: Número de bytes a mover.whence: Punto de referencia para el desplazamiento.0(os.SEEK_SET): Desde el inicio del archivo (predeterminado).1(os.SEEK_CUR): Desde la posición actual.2(os.SEEK_END): Desde el final del archivo.
with open('ejemplo.txt', 'r+', encoding='utf-8') as archivo:
print(f"Posición inicial: {archivo.tell()} bytes") # 0
contenido = archivo.read(10) # Lee los primeros 10 caracteres
print(f"Leído: '{contenido}'")
print(f"Posición actual después de leer: {archivo.tell()} bytes") # 10 (aprox. si son caracteres ASCII)
archivo.seek(0) # Vuelve al inicio
print(f"Posición después de seek(0): {archivo.tell()} bytes") # 0
archivo.seek(5, 0) # Mueve 5 bytes desde el inicio
print(f"Posición después de seek(5, 0): {archivo.tell()} bytes")
archivo.write("CAMBIO") # Sobrescribe desde la posición actual
archivo.seek(0) # Vuelve al inicio para leer el archivo modificado
print("--- Contenido modificado ---")
print(archivo.read())
Serialización con pickle
El módulo pickle permite serializar (convertir objetos Python en un flujo de bytes) y deserializar (reconstruir objetos Python a partir de ese flujo) objetos complejos de Python. Esto es útil para almacenar objetos en archivos o transmitirlos a través de la red.
Guardar un Objeto (Serializar)
import pickle
data = {'nombre': 'Alice', 'edad': 30, 'ciudades': ['Nueva York', 'Londres']}
with open('data.pkl', 'wb') as archivo:
pickle.dump(data, archivo)
print("Objeto serializado y guardado en 'data.pkl'.")
Cargar un Objeto (Deserializar)
import pickle
with open('data.pkl', 'rb') as archivo:
loaded_data = pickle.load(archivo)
print("Objeto deserializado de 'data.pkl':")
print(loaded_data)
print(f"Tipo de objeto: {type(loaded_data)}")
Funciones y Ámbito de Variables
Las funciones son bloques de código reutilizables que realizan una tarea específica. Entender cómo definirlas, su ámbito y el manejo de valores de retorno es esencial.
Definición de Funciones
Las funciones se definen usando la palabra clave def, seguida del nombre de la función, paréntesis para los parámetros y un punto y coma.
def saludar(nombre):
"""Esta función imprime un saludo."""
print(f"¡Hola, {nombre}!")
def sumar(a, b):
"""Esta función retorna la suma de dos números."""
return a + b
# Llamadas a funciones
saludar("Carlos")
resultado_suma = sumar(5, 3)
print(f"La suma es: {resultado_suma}")
La cadena de texto (docstring) después de la definición de la función sirve como documentación y se puede acceder con help(nombre_funcion).
Ámbito de Variables
El ámbito (scope) de una varible determina dónde puede ser accedida o modificada. En Python, hay principalmente dos ámbitos: local y global.
Variables Locales
Definidas dentro de una función, solo son accesibles dentro de esa función.
def mi_funcion():
variable_local = "Soy local"
print(variable_local)
mi_funcion()
# print(variable_local) # Esto causaría un NameError
Variables Globales
Definidas fuera de cualquier función, son accesibles desde cualquier parte del programa. Para modificarlas dentro de una función, se debe usar la palabra clave global.
variable_global = "Soy global"
def otra_funcion():
print(variable_global) # Acceso a la variable global
# Intentar modificarla sin 'global' crearía una nueva variable local
# variable_global = "Modificada localmente" # Esto no afectaría a la global
def modificar_global():
global variable_global # Declara que estamos usando la variable global
variable_global = "Soy global y he sido modificada"
print(variable_global)
otra_funcion() # Imprime "Soy global"
modificar_global() # Imprime "Soy global y he sido modificada"
print(variable_global) # Imprime "Soy global y he sido modificada"
Valores de Retorno
La palabra clave return se usa para enviar un valor de vuelta desde una función. Si no se especifica return, la función devuelve implícitamente None.
def calcular_area(base, altura):
area = 0.5 * base * altura
return area
area_triangulo = calcular_area(10, 5)
print(f"El área del triángulo es: {area_triangulo}")
def no_retorna_nada():
print("Esta función no usa return.")
resultado_none = no_retorna_nada()
print(f"El resultado de no_retorna_nada() es: {resultado_none}")
Funciones Especiales
(1) Funciones Lambda (Anónimas)
Son funciones pequeñas y anónimas que pueden tener cualquier número de argumentos, pero solo pueden tener una expresión. Se definen con la palabra clave lambda.
# Lambda para sumar dos números
sumar_lambda = lambda x, y: x + y
print(f"Suma con lambda: {sumar_lambda(4, 6)}")
# Lambda como argumento para otra función (ej. sorted)
lista_pares = [(1, 'b'), (3, 'a'), (2, 'c')]
lista_ordenada = sorted(lista_pares, key=lambda par: par[1]) # Ordena por el segundo elemento de la tupla
print(f"Lista ordenada por segundo elemento: {lista_ordenada}")
(2) map(): Aplicar una función a cada elemento
Aplica una función dada a cada elemento de un iterable y devuelve un iterador con los resultados. En Python 3, para ver los resultados como una lista, debe convertir el iterador explícitamente.
numeros = [1, 2, 3, 4, 5]
# Duplicar cada número
duplicados = list(map(lambda x: x * 2, numeros))
print(f"Números duplicados: {duplicados}")
# Convertir a cadena
cadenas = list(map(str, numeros))
print(f"Números como cadenas: {cadenas}")
(3) filter(): Filtrar elementos
Construye un iterador a partir de los elementos de un iterable para los que una función devuelve True.
edades = [12, 17, 18, 25, 15, 20]
# Filtrar edades mayores o iguales a 18
adultos = list(filter(lambda edad: edad >= 18, edades))
print(f"Edades de adultos: {adultos}")
(4) functools.reduce(): Aplicación acumulativa
Aplica una función a los elementos de un iterable de forma acumulativa, reduciéndolo a un solo valor. Requiere importar desde el módulo functools.
from functools import reduce
numeros = [1, 2, 3, 4, 5]
# Sumar todos los números (acumulativo)
suma_total = reduce(lambda x, y: x + y, numeros)
print(f"Suma total con reduce: {suma_total}")
# Encontrar el producto de todos los números
producto_total = reduce(lambda x, y: x * y, numeros)
print(f"Producto total con reduce: {producto_total}")
(5) yield: Generadores
La palabra clave yield se utiliza para definir funciones generadoras. Una función generadora es una función que, en lugar de devolver un solo valor con return, produce una secuencia de valores uno por uno, suspendiendo su ejecución entre cada valor.
def generador_cuadrados(n):
for i in range(n):
yield i * i # 'yield' produce un valor y pausa la ejecución
# Usar el generador
for cuadrado in generador_cuadrados(5):
print(f"Cuadrado: {cuadrado}")
# También se puede convertir a lista si se necesita todos los valores de una vez
lista_cuadrados = list(generador_cuadrados(3))
print(f"Lista de cuadrados: {lista_cuadrados}")
Estructuras de Control de Flujo
Las estructuras de control de flujo permiten dictar el orden en que se ejecutan las instrucciones en un programa, posibilitando la toma de decisiones y la repetición de tareas.
Sentencias Condicionales: if, elif, else
Permiten ejecutar bloques de código específicos basándose en si una condición es verdadera o falsa.
puntuacion = 75
if puntuacion >= 90:
print("Calificación: A")
elif puntuacion >= 80:
print("Calificación: B")
elif puntuacion >= 70:
print("Calificación: C")
else:
print("Calificación: D")
Bucle for
El bucle for se usa para iterar sobre los elementos de una secuencia (lista, tupla, cadena, etc.) o cualquier otro objeto iterable.
frutas = ["manzana", "banana", "cereza"]
for fruta in frutas:
print(f"Me gusta la {fruta}.")
print("\n--- Con range() ---")
for i in range(3): # Itera 3 veces (0, 1, 2)
print(f"Iteración número {i}")
Bucle while
El bucle while ejecuta un bloque de código repetidamente siempre y cuando una condición sea verdadera. Es importante asegurarse de que la condición eventualmente se vuelva falsa para evitar bucles infinitos.
contador = 0
while contador < 3:
print(f"Contador: {contador}")
contador += 1 # Incrementa el contador para que la condición eventualmente sea falsa
Control de Bucle: continue y break
break: Termina el bucle actual completamente y salta a la instrucción que sigue inmediatamente al bucle.continue: Salta el resto de la iteración actual y pasa a la siguiente iteración del bucle.
print("--- Ejemplo con break ---")
for i in range(10):
if i == 5:
break # El bucle se detiene cuando i es 5
print(i)
print("\n--- Ejemplo con continue ---")
for i in range(10):
if i % 2 == 0: # Si i es par
continue # Salta esta iteración, no imprime el número par
print(i) # Solo imprime números impares
Tipos de Datos Secuenciales
Las secuencias son colecciones ordenadas de elementos. Python ofrece varios tipos de datos secuenciales, siendo las cadenas (str), listas (list) y tuplas (tuple) los más comunes.
Propiedades Comunes de las Secuencias
- Ordenadas: Los elementos tienen una posición definida (índice).
- Indexables: Se puede acceder a los elementos por su índice (
secuencia[indice]). - Cortables (Slicing): Se pueden extraer sub-secuencias (
secuencia[inicio:fin:paso]).
Operaciones Genéricas de Secuencia
mi_lista = [10, 20, 30, 40, 50]
mi_cadena = "Python"
mi_tupla = (1, 2, 3)
# Acceso por índice
print(f"Elemento en índice 1 de la lista: {mi_lista[1]}") # 20
print(f"Carácter en índice 0 de la cadena: {mi_cadena[0]}") # P
# Slicing (corte)
print(f"Sub-lista: {mi_lista[1:4]}") # [20, 30, 40]
print(f"Sub-cadena: {mi_cadena[2:]}") # thon
# Concatenación (+)
otra_lista = [60, 70]
print(f"Listas concatenadas: {mi_lista + otra_lista}")
# Repetición (*)
print(f"Cadena repetida: {mi_cadena * 2}") # PythonPython
# Pertenencia (in, not in)
print(f"¿30 está en mi_lista? {'30' in mi_lista}") # False (tipos diferentes)
print(f"¿'y' está en mi_cadena? {'y' in mi_cadena}") # True
Cadenas (str)
Las cadenas son secuencias inmutables de caracteres. Una vez creadas, no se pueden modificar.
Métodos Comunes de Cadenas
texto = " Hola Mundo PYTHON! "
print(f"Original: '{texto}'")
print(f"Longitud: {len(texto)}")
# Modificación de mayúsculas/minúsculas
print(f"Minúsculas: '{texto.lower()}'")
print(f"Mayúsculas: '{texto.upper()}'")
print(f"Capitalizar: '{texto.capitalize()}'") # Primera letra de toda la cadena
print(f"Título: '{texto.title()}'") # Primera letra de cada palabra
# Eliminar espacios en blanco
print(f"Sin espacios al inicio/fin: '{texto.strip()}'")
print(f"Sin espacios a la izquierda: '{texto.lstrip()}'")
print(f"Sin espacios a la derecha: '{texto.rstrip()}'")
# Buscar y reemplazar
print(f"Índice de 'Mundo': {texto.find('Mundo')}") # Retorna -1 si no encuentra
print(f"Contar 'o': {texto.count('o')}")
print(f"Reemplazar 'Mundo' por 'Amigo': '{texto.replace('Mundo', 'Amigo')}'")
# Dividir y Unir
frase = "Python es divertido y potente"
palabras = frase.split(' ')
print(f"Dividir por espacio: {palabras}")
nueva_frase = '-'.join(palabras)
print(f"Unir con guión: {nueva_frase}")
# Verificación
print(f"¿Termina con '!'? {texto.strip().endswith('!')}")
print(f"¿Empieza con 'Hola'? {texto.strip().startswith('Hola')}")
Listas (list)
Las listas son secuencias mutables (se pueden modificar después de su creación) de elementos, que pueden ser de diferentes tipos.
Métodos Comunes de Listas
mis_numeros = [3, 1, 4, 1, 5, 9, 2]
print(f"Original: {mis_numeros}")
# Añadir elementos
mis_numeros.append(6) # Añade al final
print(f"Después de append(6): {mis_numeros}")
mis_numeros.insert(2, 7) # Inserta 7 en índice 2
print(f"Después de insert(2, 7): {mis_numeros}")
# Extender con otra secuencia
otras_cifras = [8, 0]
mis_numeros.extend(otras_cifras)
print(f"Después de extend([8, 0]): {mis_numeros}")
# Eliminar elementos
mis_numeros.remove(1) # Elimina la primera ocurrencia de 1
print(f"Después de remove(1): {mis_numeros}")
elemento_eliminado = mis_numeros.pop(0) # Elimina y devuelve el elemento en índice 0
print(f"Después de pop(0): {mis_numeros}, Eliminado: {elemento_eliminado}")
# Ordenar y Revertir
mis_numeros.sort() # Ordena la lista in-place
print(f"Después de sort(): {mis_numeros}")
mis_numeros.reverse() # Invierte el orden in-place
print(f"Después de reverse(): {mis_numeros}")
# Contar y Encontrar
print(f"Número de '1's: {mis_numeros.count(1)}")
print(f"Índice del primer '5': {mis_numeros.index(5)}")
# Copiar listas (Copia Superficial vs Profunda)
lista_original = [1, 2, ['a', 'b']]
lista_copia_superficial = list(lista_original) # o lista_original[:]
lista_copia_profunda = copy.deepcopy(lista_original) # Requiere import copy
lista_original.append(3)
lista_original[2].append('c') # Esto afecta a la copia superficial
print(f"Original: {lista_original}")
print(f"Copia Superficial: {lista_copia_superficial}") # Contendrá 'c'
print(f"Copia Profunda: {lista_copia_profunda}") # No contendrá 'c'
Tuplas (tuple)
Las tuplas son secuencias inmutables de elementos. Son similares a las listas, pero no se pueden modificar una vez creadas.
Definición y Acceso
mi_tupla = (10, "Python", 3.14, True)
otra_tupla = 20, "Java" # Los paréntesis son opcionales para la creación
print(f"Tupla: {mi_tupla}")
print(f"Elemento en índice 1: {mi_tupla[1]}") # Python
Empaquetado y Desempaquetado de Tuplas
# Empaquetado: asignar múltiples valores a una tupla
coordenadas = 10, 20
print(f"Coordenadas empaquetadas: {coordenadas}") # (10, 20)
# Desempaquetado: asignar elementos de una tupla a variables individuales
x, y = coordenadas
print(f"x: {x}, y: {y}") # x: 10, y: 20
# Útil para retornar múltiples valores de una función
def obtener_info_usuario():
return "Ana", 28, "anal@example.com"
nombre, edad, email = obtener_info_usuario()
print(f"Nombre: {nombre}, Edad: {edad}, Email: {email}")
Funciones Integradas Útiles para Secuencias
len(secuencia): Retorna la longitud de la secuencia.max(secuencia): Retorna el elemento más grande.min(secuencia): Retorna el elemento más pequeño.sum(iterable, start=0): Retorna la suma de los elementos de un iterable.enumerate(iterable, start=0): Devuelve un iterador que produce tuplas(índice, valor).zip(iterable1, iterable2, ...): Combina elementos de múltiples iterables en tuplas.sorted(iterable, key=None, reverse=False): Devuelve una nueva lista ordenada a partir de los elementos del iterable. No modifica el original.reversed(secuencia): Devuelve un iterador que produce elementos en orden inverso. No modifica el original.
nombres = ["Elena", "David", "Carlos", "Beatriz", "Ana"]
puntuaciones = [85, 92, 78, 95, 88]
# enumerate
print("--- Enumerar nombres ---")
for indice, nombre in enumerate(nombres):
print(f"{indice+1}. {nombre}")
# zip
print("\n--- Combinar con zip ---")
for nombre, puntuacion in zip(nombres, puntuaciones):
print(f"{nombre}: {puntuacion} puntos")
# sorted
print(f"\nLista de nombres original: {nombres}")
nombres_ordenados = sorted(nombres)
print(f"Nombres ordenados (nueva lista): {nombres_ordenados}")
# sorted con una clave personalizada
# Ordenar la lista de nombres por su longitud
nombres_por_longitud = sorted(nombres, key=len)
print(f"Nombres ordenados por longitud: {nombres_por_longitud}")
# sorted con clave personalizada para una lista de tuplas (nombre, puntuacion)
alumnos_puntuaciones = list(zip(nombres, puntuaciones))
print(f"Alumnos y puntuaciones: {alumnos_puntuaciones}")
# Ordenar por puntuación (segundo elemento de cada tupla)
alumnos_ordenados_por_puntuacion = sorted(alumnos_puntuaciones, key=lambda item: item[1], reverse=True)
print(f"Alumnos ordenados por puntuación (descendente): {alumnos_ordenados_por_puntuacion}")
# reversed
print("\n--- Nombres en orden inverso (iterador) ---")
for nombre_inverso in reversed(nombres):
print(nombre_inverso)
# sum, max, min
print(f"\nPuntuación máxima: {max(puntuaciones)}")
print(f"Puntuación mínima: {min(puntuaciones)}")
print(f"Suma total de puntuaciones: {sum(puntuaciones)}")
Diccionarios (dict)
Los diccionarios son colecciones desordenadas (en versiones anteriores a Python 3.7, ahora mantienen el orden de inserción) de pares clave-valor. Las claves deben ser únicas e inmutables (cadenas, números, tuplas), mientras que los valores pueden ser de cualquier tipo.
Creación y Acceso
# Crear un diccionario
estudiante = {
"nombre": "Elena",
"edad": 22,
"carrera": "Ingeniería Informática",
"cursos": ["Programación", "Bases de Datos", "Redes"]
}
print(f"Estudiante: {estudiante}")
# Acceder a un valor por su clave
print(f"Nombre del estudiante: {estudiante['nombre']}")
print(f"Edad del estudiante: {estudiante['edad']}")
# Intentar acceder a una clave inexistente causaría un KeyError
# print(estudiante['direccion']) # Error
Modificación y Adición
# Añadir una nueva clave-valor
estudiante["universidad"] = "Universidad XYZ"
print(f"Después de añadir universidad: {estudiante}")
# Modificar un valor existente
estudiante["edad"] = 23
print(f"Después de actualizar edad: {estudiante}")
Eliminación de Elementos
# Eliminar con 'del'
del estudiante["carrera"]
print(f"Después de eliminar carrera: {estudiante}")
# Eliminar con 'pop()' (devuelve el valor eliminado)
cursos_eliminados = estudiante.pop("cursos")
print(f"Después de eliminar cursos con pop(): {estudiante}, Cursos eliminados: {cursos_eliminados}")
Método .get() para Acceso Seguro
El método .get() permite acceder a un valor por su clave de forma segura. Si la clave no existe, devuelve None o un valor predeterminado especificado.
print(f"Obtener nombre con .get(): {estudiante.get('nombre')}")
print(f"Obtener dirección (no existe): {estudiante.get('direccion')}") # None
print(f"Obtener dirección (con valor por defecto): {estudiante.get('direccion', 'Desconocida')}")
Iteración sobre Diccionarios
# Iterar sobre las claves (predeterminado)
print("--- Claves ---")
for clave in estudiante:
print(clave)
# Iterar sobre los valores
print("\n--- Valores ---")
for valor in estudiante.values():
print(valor)
# Iterar sobre pares clave-valor (recomendado)
print("\n--- Claves y Valores ---")
for clave, valor in estudiante.items():
print(f"{clave}: {valor}")
Conjuntos (set)
Los conjuntos son colecciones dseordenadas de elementos únicos. Son mutables y no permiten elementos duplicados. Son ideales para operaciones matemáticas de conjuntos como unión, intersección y diferencia.
Creación de Conjuntos
# Crear un conjunto a partir de una lista (elimina duplicados automáticamente)
lista_numeros = [1, 2, 2, 3, 4, 4, 5]
mi_conjunto = set(lista_numeros)
print(f"Conjunto desde lista: {mi_conjunto}") # {1, 2, 3, 4, 5} (orden puede variar)
# Crear un conjunto vacío
conjunto_vacio = set()
print(f"Conjunto vacío: {conjunto_vacio}")
# Crear un conjunto directamente con llaves (¡cuidado con el diccionario vacío!)
conjunto_directo = {6, 7, 8}
print(f"Conjunto directo: {conjunto_directo}")
Añadir y Eliminar Elementos
mi_conjunto.add(6) # Añade un elemento
print(f"Después de add(6): {mi_conjunto}")
mi_conjunto.add(2) # Intentar añadir un duplicado no tiene efecto
print(f"Después de add(2) (sin cambios): {mi_conjunto}")
mi_conjunto.discard(3) # Elimina 3 si existe, no da error si no existe
print(f"Después de discard(3): {mi_conjunto}")
# mi_conjunto.remove(10) # Esto daría un KeyError si 10 no está en el conjunto
mi_conjunto.pop() # Elimina y devuelve un elemento arbitrario
print(f"Después de pop(): {mi_conjunto}")
mi_conjunto.clear() # Elimina todos los elementos
print(f"Después de clear(): {mi_conjunto}")
Operaciones de Conjuntos
set_a = {1, 2, 3, 4, 5}
set_b = {4, 5, 6, 7, 8}
# Unión
union_sets = set_a.union(set_b)
print(f"Unión de A y B: {union_sets}") # {1, 2, 3, 4, 5, 6, 7, 8}
# Intersección
interseccion_sets = set_a.intersection(set_b)
print(f"Intersección de A y B: {interseccion_sets}") # {4, 5}
# Diferencia (elementos en A pero no en B)
diferencia_sets = set_a.difference(set_b)
print(f"Diferencia A - B: {diferencia_sets}") # {1, 2, 3}
# Diferencia simétrica (elementos en A o B, pero no en ambos)
simetrica_sets = set_a.symmetric_difference(set_b)
print(f"Diferencia simétrica de A y B: {simetrica_sets}") # {1, 2, 3, 6, 7, 8}
# Actualizar un conjunto con otra operación
set_a.update(set_b) # set_a ahora es la unión de set_a y set_b
print(f"Set A después de update(Set B): {set_a}")
# Verificar subconjunto/superconjunto
set_c = {1, 2}
print(f"¿Set C es subconjunto de Set A? {set_c.issubset(set_a)}")
print(f"¿Set A es superconjunto de Set C? {set_a.issuperset(set_c)}")
# Verificar disyunción (no tienen elementos en común)
set_d = {9, 10}
print(f"¿Set A y Set D son disjuntos? {set_a.isdisjoint(set_d)}")
Programación Orientada a Objetos: Módulos, Clases y Objetos
La Programación Orientada a Objetos (POO) es un paradigma de programación que utiliza "objetos" para diseñar aplicaciones y programas informáticos. Python es un lenguaje multiparadigma, con un fuerte soporte para la POO.
Módulos vs. Clases
-
Módulo: Es simplemente un archivo
.pyque contiene código Python (variables, funciones, clases). Sirve para organizar el código en archivos lógicos y reutilizables. Se importa conimport nombre_modulo. ```pythonmi_utilidades.py
def saludar(nombre): return f"¡Hola, {nombre} desde el módulo!"
CONSTANTE = 123
En otro archivo.py
import mi_utilidades print(mi_utilidades.saludar("Juan")) print(mi_utilidades.CONSTANTE)
-
Clase: Es una plantilla o "plano" para crear objetos. Define un conjunto de atributos (variables) y métodos (funciones) que los objetos de esa clase tendrán. Una clase encapsula datos y comportamiento.
Clases y Objetos
Un objeto es una instancia de una clase. La clase define la estructura y el comportamiento, y el objeto es una entidad concreta creada a partir de esa estructura.
Definición de Clases
Las clases se definen usando la palabra clave class.
class Gato:
# Atributo de clase: compartido por todas las instancias
especie = "felino"
def __init__(self, nombre, edad):
# Método constructor: se llama al crear una nueva instancia
# 'self' se refiere a la instancia actual del objeto
self.nombre = nombre # Atributo de instancia
self.edad = edad # Atributo de instancia
print(f"Gato {self.nombre} creado.")
def maullar(self):
"""Método de instancia: comportamiento del objeto."""
return f"{self.nombre} dice: ¡Miau!"
def describir(self):
"""Docstring para el método describir."""
return f"Soy {self.nombre}, un {self.especie} de {self.edad} años."
# Instanciación de objetos (creación de objetos a partir de la clase)
gato1 = Gato("Garfield", 5)
gato2 = Gato("Tom", 3)
# Acceso a atributos y métodos
print(f"{gato1.nombre} tiene {gato1.edad} años.")
print(gato2.maullar())
print(gato1.describir())
# Acceso al atributo de clase
print(f"Todos los gatos son de la especie: {Gato.especie}")
print(f"{gato1.nombre} es de la especie: {gato1.especie}")
# Se puede obtener ayuda sobre la clase y sus métodos
# help(Gato)
# help(Gato.maullar)
El Parámetro self
En Python, los métodos de clase deben tener un primer parámetro llamado self (por convención, podría ser cualquier nombre). self es una referencia a la instancia del objeto que está llamando al método. A través de self, un método puede acceder a los atributos y otros métodos de esa misma instancia.
Herencia
La herencia permite que una clase (subclase o clase hija) adquiera los atributos y métodos de otra clase (superclase o clase padre). Esto promueve la reutilización de código.
class Animal:
def __init__(self, nombre):
self.nombre = nombre
def respirar(self):
return f"{self.nombre} está respirando."
class Mamifero(Animal):
def __init__(self, nombre, tipo_pelaje):
super().__init__(nombre) # Llama al constructor de la clase padre
self.tipo_pelaje = tipo_pelaje
def amamantar(self):
return f"{self.nombre} está amamantando."
class Perro(Mamifero):
def __init__(self, nombre, tipo_pelaje, raza):
super().__init__(nombre, tipo_pelaje)
self.raza = raza
def ladrar(self):
return f"{self.nombre} dice: ¡Guau, guau!"
# Crear instancias de las clases
animal = Animal("Ser vivo")
mamifero = Mamifero("León", "melena")
perro = Perro("Fido", "corto", "Labrador")
print(animal.respirar())
print(mamifero.respirar())
print(mamifero.amamantar())
print(perro.respirar())
print(perro.amamantar())
print(perro.ladrar())
print(f"{perro.nombre} es de raza {perro.raza} y tiene pelaje {perro.tipo_pelaje}.")
En el ejemplo anterior, Perro es un tipo de Mamifero (relación "es-un"), y Mamifero es un tipo de Animal. Esto significa que un Perro hereda todas las funcionalidades de Mamifero y Animal.
Atributos de Clase y Atributos de Instancia
- Atributos de Clase: Son compartidos por todas las instancias de la clase. Se definen directamente dentro de la clase, pero fuera de cualquier método.
- Atributos de Instancia: Son únicos para cada instancia del objeto. Se definen dentro del método
__init__usandoself.nombre_atributo.
Composición
La composición es otra forma de reutilizar código, donde una clase contiene una instancia de otra clase como uno de sus atributos (relación "tiene-un").
class Motor:
def __init__(self, tipo):
self.tipo = tipo
def arrancar(self):
return f"Motor {self.tipo} arrancado."
class Coche:
def __init__(self, marca, modelo, tipo_motor):
self.marca = marca
self.modelo = modelo
self.motor = Motor(tipo_motor) # El coche 'tiene-un' motor
def conducir(self):
return f"El {self.marca} {self.modelo} está conduciendo. {self.motor.arrancar()}"
mi_coche = Coche("Toyota", "Corolla", "gasolina")
print(mi_coche.conducir())
Aquí, la clase Coche tiene una instancia de la clase Motor, lo que demuestra la composición.