En esta páginaFunciones e imports
Funciones e imports
- Nivel: principiante
- Úsala cuando: quieras reutilizar una operación o importar código
- Conocimientos previos útiles: colecciones, condicionales y bucles
En esta página convertirás un reporte escolar escrito como un bloque largo en funciones que puedas probar y reutilizar. Después podrás completar una práctica en dos archivos para aplicar funciones, colecciones e imports.
Qué puedes consultar aquí
- definir una función con
defy llamarla por su nombre; - distinguir parámetros de argumentos;
- guardar y usar el valor de
return, sin confundirlo con la salida deprint; - predecir dónde puede usarse un nombre local;
- dividir un problema en funciones con tareas separadas;
- importar un módulo estándar y funciones de un archivo vecino;
- ejecutar un programa de dos archivos desde una misma carpeta.
Definir no es ejecutar
Una definición crea la función y asocia su nombre con un cuerpo de instrucciones. Este bloque solo contiene la definición, así que no muestra nada al ejecutarlo:
def saludar():
print("Hola, equipo")
def inicia la definición. Después aparecen el nombre saludar, los paréntesis, los dos puntos y el cuerpo indentado. Python ejecuta ese cuerpo cuando encuentra una llamada, no cuando procesa la definición.
Añade saludar() debajo de la definición:
def saludar():
print("Hola, equipo")
saludar()
La salida es:
Hola, equipo
Los paréntesis de la última línea indican la llamada. En un script normal, Python debe procesar la definición antes de llegar a esa llamada. Prueba cambiar el mensaje del cuerpo y ejecuta otra vez el archivo.
Parámetros y argumentos
Un parámetro es un nombre que aparece en la definición y representa una entrada. Un argumento es el valor concreto enviado durante una llamada.
def crear_mensaje(nombre, puntos):
return f"{nombre} obtuvo {puntos} puntos"
mensaje = crear_mensaje("Luz", 9)
print(mensaje)
La salida es Luz obtuvo 9 puntos. En la definición, nombre y puntos son parámetros. En la llamada, "Luz" y 9 son argumentos.
Estos argumentos son posicionales: el primero se asocia con nombre y el segundo con puntos. Intercambiarlos también cambia el significado del mensaje. Prueba crear_mensaje(9, "Luz") y observa por qué el orden forma una frase incorrecta aunque el código sea válido.
La siguiente llamada tiene un recorrido que conviene seguir paso a paso:
def duplicar(numero):
resultado = numero * 2
return resultado
puntos = duplicar(6)
print(puntos)
Primero comienza la ejecución de duplicar. El argumento 6 se asocia con el parámetro numero; luego se calcula resultado = 12. return devuelve ese valor y la asignación lo asocia con el nombre puntos.
Recorrido de una llamada de función
Avanza por las etapas y sigue los argumentos, el cuerpo de la función y el valor de retorno.
def duplicar(numero):
resultado = numero * 2
return resultado
puntos = duplicar(6)
print(puntos)puntos = duplicar(6)- numero
- sin asignar
- resultado
- sin asignar
- return
- pendiente
- puntos
- sin asignar
Paso 1, Llamada: La llamada comienza con el argumento 6.
return entrega; print muestra
print muestra una representación en pantalla. return envía un valor al lugar donde se hizo la llamada y termina esa ejecución de la función.
def mostrar_doble(numero):
print(numero * 2)
valor = mostrar_doble(7)
print(valor)
La primera línea de salida es 14, producida dentro de la función. La segunda es None: mostrar_doble llegó al final sin return, por lo que devolvió None. El propio print también devuelve None.
Ahora el cálculo sí se devuelve y puede participar en otra operación:
def calcular_doble(numero):
return numero * 2
resultado = calcular_doble(7)
print(resultado + 1)
La salida es 15. También podrías comparar resultado, guardarlo en una lista o pasarlo a otra función. Una función puede devolver una lista, un diccionario o una tupla; el ejemplo usa un número para mantener visible el recorrido.
Prueba cambiar return numero * 2 por return numero * 3. La modificación debe afectar el cálculo sin cambiar la línea que lo muestra.
Alcance local
El alcance es la zona del programa donde puede usarse un nombre. Los parámetros y las variables creadas dentro de una función son locales a esa función.
curso = "Python"
def crear_etiqueta(nombre):
mensaje = f"{nombre} estudia {curso}"
return mensaje
etiqueta = crear_etiqueta("Luz")
print(etiqueta)
# print(mensaje) # NameError: mensaje solo existe dentro de la función
nombre y mensaje son locales. La función sí puede leer curso, definido fuera de ella. Si quitas el comentario de la última línea, Python produce NameError porque mensaje no está disponible en ese punto.
Crear dentro de una función otro nombre llamado curso no cambia automáticamente el curso exterior. Para comunicar datos con claridad, prefiere entradas mediante parámetros y salidas mediante return; aquí no hace falta modificar variables globales.
Funciones lambda
Una función lambda es una función anónima: se escribe con la palabra lambda, no recibe nombre con def y su cuerpo es una sola expresión. lambda nota: nota + 1 equivale a una función que recibe nota y devuelve nota + 1. Antes de los dos puntos van los parámetros; después, la expresión cuyo valor se devuelve sin escribir return.
Una lambda suele escribirse directamente como argumento de otra función. sorted devuelve una lista nueva ordenada sin modificar la original y max devuelve el elemento mayor. Ambas aceptan el parámetro key, que recibe una función. Python la llama con cada elemento y compara los valores que devuelve, no los elementos completos:
promedios = [("Luz", 8.2), ("Ana", 9.0), ("Beto", 7.5)]
ordenados = sorted(promedios, key=lambda registro: registro[1])
mejor = max(promedios, key=lambda registro: registro[1])
print(ordenados)
print(mejor)
La salida es:
[('Beto', 7.5), ('Luz', 8.2), ('Ana', 9.0)]
('Ana', 9.0)
registro[1] es el promedio de cada tupla, así que ese valor decide el orden y el máximo. Sin key, Python compara las tuplas empezando por el nombre: max(promedios) devuelve ('Luz', 8.2) porque "Luz" es la última cadena en orden alfabético. Prueba añadir reverse=True a sorted y comprueba que ('Ana', 9.0) queda primero.
map aplica una función a cada elemento. filter conserva los elementos para los que la función produce un resultado verdadero, como la condición de un if. Ambas entregan un objeto que produce los valores al recorrerlo; list los reúne para mostrarlos:
notas = [6, 9, 7, 10]
en_escala_100 = list(map(lambda nota: nota * 10, notas))
altas = list(filter(lambda nota: nota >= 8, notas))
print(en_escala_100)
print(altas)
La salida es:
[60, 90, 70, 100]
[9, 10]
Sin list, print mostraría algo como <map object at 0x...> en lugar de los valores.
Con una comprensión de lista, las mismas listas se escriben así:
notas = [6, 9, 7, 10]
en_escala_100 = [nota * 10 for nota in notas]
altas = [nota for nota in notas if nota >= 8]
print(en_escala_100)
print(altas)
La salida vuelve a ser [60, 90, 70, 100] y [9, 10]. La comprensión se lee de izquierda a derecha, como «nota por 10 para cada nota en notas», no necesita lambda y ya devuelve una lista. La diferencia crece al combinar ambas tareas: [nota * 10 for nota in notas if nota >= 8] devuelve [90, 100], mientras que la versión con map y filter anida dos lambdas: list(map(lambda nota: nota * 10, filter(lambda nota: nota >= 8, notas))).
Si la función debe reutilizarse o su cuerpo no cabe en una expresión, defínela con def y un nombre.
Descomponer antes de programar
Este bloque calcula un promedio, determina un estado y construye un reporte en un solo flujo:
nombre = "Luz"
calificaciones = [8, 9, 10]
promedio = sum(calificaciones) / len(calificaciones)
if promedio >= 8:
estado = "dominado"
else:
estado = "en progreso"
reporte = f"{nombre}: {promedio:.1f}, {estado}"
print(reporte)
Funciona, pero reúne tres tareas en un solo flujo. La descomposición separa tareas que tienen entradas y resultados identificables.
def calcular_promedio(calificaciones):
return sum(calificaciones) / len(calificaciones)
def determinar_estado(promedio):
if promedio >= 8:
return "dominado"
return "en progreso"
def crear_reporte(nombre, promedio, estado):
return f"{nombre}: {promedio:.1f}, {estado}"
notas = [8, 9, 10]
media = calcular_promedio(notas)
situacion = determinar_estado(media)
print(crear_reporte("Luz", media, situacion))
Cada función realiza una tarea, comienza con un verbo y recibe solo los datos necesarios. No existe un máximo universal de líneas: la separación depende de la responsabilidad. Modifica el límite de determinar_estado y comprueba que las otras funciones no necesitan cambios.
Construye un reporte de varias líneas
Una cadena puede contener saltos de línea. Para construir un reporte cuyo tamaño depende de los datos, comienza con una lista de líneas, agrega cada línea con append y únelas al final con "\n".join(lineas). append modifica la lista; join devuelve una sola cadena y coloca el separador "\n" entre elementos.
def determinar_estado(promedio):
if promedio >= 8:
return "dominado"
return "en progreso"
def crear_reporte(nombre, promedios_por_materia):
lineas = [f"Estudiante: {nombre}"]
for materia, promedio in promedios_por_materia.items():
estado = determinar_estado(promedio)
lineas.append(f"{materia}: {promedio:.1f}, {estado}")
lineas.append(f"Materias registradas: {len(promedios_por_materia)}")
return "\n".join(lineas)
promedios = {"Matemáticas": 8.5, "Historia": 7.0}
reporte = crear_reporte("Luz", promedios)
print(reporte)
La salida es:
Estudiante: Luz
Matemáticas: 8.5, dominado
Historia: 7.0, en progreso
Materias registradas: 2
La función devuelve todo el reporte y no imprime durante el recorrido. Así, quien llama decide si mostrarlo, guardarlo o usarlo de otra forma. En el proyecto aplicarás el mismo patrón y añadirás la materia por reforzar como última línea.
Imports y módulos
Un módulo es un archivo Python que puede importarse. math pertenece a la biblioteca estándar, instalada junto con Python:
import math
print(math.sqrt(81))
La salida es 9.0. El nombre math.sqrt deja visible que sqrt procede de math. Los imports suelen colocarse al inicio del archivo.
También puedes crear un módulo. Crea una carpeta vacía y guarda este primer archivo como herramientas_estudio.py:
def calcular_promedio(calificaciones):
return sum(calificaciones) / len(calificaciones)
def crear_reporte(nombre, promedio):
return f"{nombre}: {promedio:.1f}"
En la misma carpeta, guarda el segundo archivo como programa.py:
from herramientas_estudio import calcular_promedio, crear_reporte
notas = [8, 9, 10]
promedio = calcular_promedio(notas)
print(crear_reporte("Luz", promedio))
Abre una terminal en esa carpeta y ejecuta python programa.py. Algunos sistemas usan python3 programa.py. La salida esperada es Luz: 9.0.
Al importar el módulo por primera vez en un proceso, Python ejecuta sus instrucciones de nivel superior. Por eso herramientas_estudio.py contiene definiciones, pero no una demostración que imprima resultados. Importar tampoco copia y pega el archivo. Evita la variante con asterisco porque oculta el origen de cada nombre.
Cambia una nota en programa.py y vuelve a ejecutar el comando. Si aparece ModuleNotFoundError, confirma que ambos nombres terminan en .py y que los archivos están en la misma carpeta.
Errores comunes
Para cada caso, predice el resultado, ejecútalo, identifica la línea que falla y explica la corrección.
- Esta llamada aparece antes de que Python procese la definición. Produce
NameError; mueve la llamada debajo dedef.
saludar()
def saludar():
print("Hola")
- Esta función imprime el promedio, pero no lo devuelve.
resultadovaleNoneyresultado + 1produceTypeError; devuelve el cálculo y muéstralo fuera.
def calcular_promedio(calificaciones):
print(sum(calificaciones) / len(calificaciones))
resultado = calcular_promedio([8, 9, 10])
print(resultado + 1)
promedioes local y usarlo fuera produceNameError. Asigna el retorno a un nombre del programa.
def calcular_promedio(calificaciones):
promedio = sum(calificaciones) / len(calificaciones)
return promedio
calcular_promedio([8, 9, 10])
print(promedio)
Correcciones razonadas
El primer arreglo cambia el orden, no el cuerpo. Los otros dos hacen explícito el recorrido del dato:
def saludar():
print("Hola")
saludar()
def calcular_promedio(calificaciones):
return sum(calificaciones) / len(calificaciones)
resultado = calcular_promedio([8, 9, 10])
print(resultado + 1)
La asignación conserva el valor devuelto en un nombre disponible para el resto del programa. Los textos completos de las excepciones pueden variar entre versiones de Python, pero sus clases siguen siendo NameError y TypeError en estos casos.
Práctica
Traza
Sin ejecutar el código de duplicar(6), escribe los valores de numero, resultado y puntos en cada etapa. Después ejecútalo y compara tu traza con la salida. Explica en qué momento existe cada nombre.
Modifica
Completa convertir_a_porcentaje para que entregue el decimal multiplicado por 100. Luego usa su retorno dentro de crear_reporte.
def convertir_a_porcentaje(decimal):
pass
def crear_reporte(porcentaje):
return f"Avance: {porcentaje:.1f}%"
Con la entrada 0.85, la salida debe ser Avance: 85.0%. Pista: pass permite que una función quede vacía, pero esa función devuelve None; reemplázalo con un return.
Solución: revisa después de intentarlo.
def convertir_a_porcentaje(decimal):
return decimal * 100
def crear_reporte(porcentaje):
return f"Avance: {porcentaje:.1f}%"
avance = convertir_a_porcentaje(0.85)
print(crear_reporte(avance))
Crea
Escribe encontrar_menor(calificaciones) sin usar min. Recorre una lista no vacía, conserva el menor valor y devuélvelo. Prueba las listas [8, 6, 9] y [10, 10, 10]; los resultados deben ser 6 y 10.
Práctica opcional
Crea conversiones.py:
def convertir_a_porcentaje(decimal):
return decimal * 100
Crea programa.py en la misma carpeta:
from conversiones import convertir_a_porcentaje
resultado = convertir_a_porcentaje(0.85)
print(f"{resultado:.1f}%")
Ejecuta python programa.py. La salida debe ser 85.0%. Después cambia 0.85 por otro decimal y predice la salida antes de ejecutar. Si aparece ModuleNotFoundError, comprueba que ambos archivos estén en la misma carpeta y que el nombre del import coincida con conversiones.py.
Lista de comprobación
Comprueba cada afirmación con código ejecutado:
- Definí una función y la llamé después de su definición.
- Señalé parámetros y argumentos en una llamada propia.
- Usé un retorno en otra operación y expliqué por qué
printno lo reemplaza. - Predije un
NameErrorcausado por una variable local. - Ordené una lista de tuplas con
sorted(key=lambda …)y reescribí unmapofiltercomo comprensión de lista. - Separé un reporte en funciones con responsabilidades distintas.
- Importé un módulo estándar y funciones de mi propio módulo.
- Ejecuté el proyecto desde dos archivos en la misma carpeta.