Módulo 1 · Lección 33 de 59
Parámetros y argumentos
Cómo pasarle datos a una función, la diferencia entre parámetro y argumento, y cuándo conviene nombrarlos al llamar.
La función imprimir_cabecera() de la lección anterior tiene un defecto: siempre imprime exactamente lo mismo. Sirve para una tienda y para nada más.
Una función se vuelve útil de verdad cuando recibe datos de fuera y trabaja con ellos. Eso es lo que hay dentro de los paréntesis, que hasta ahora estaban vacíos.
Un hueco para el dato#
Escribe un nombre dentro de los paréntesis de la definición y ese nombre pasa a estar disponible dentro de la función como si fuera una variable:
def saludar(nombre):
print(f"Hola, {nombre}. Bienvenido a la tienda.")
saludar("Ana")
saludar("Luis")Hola, Ana. Bienvenido a la tienda.
Hola, Luis. Bienvenido a la tienda.La misma función, dos resultados distintos. En la primera llamada nombre vale "Ana"; en la segunda vale "Luis". Ese hueco es lo que hace que una función sea reutilizable en lugar de un simple atajo.
Parámetro no es lo mismo que argumento#
Las dos palabras se confunden constantemente, incluso entre profesionales, pero la distinción es sencilla y vale la pena tenerla clara porque los mensajes de error usan los términos con precisión:
| Término | Dónde aparece | En el ejemplo |
|---|---|---|
| Parámetro | En la definición, entre los paréntesis del def | nombre |
| Argumento | En la llamada, el valor concreto que pasas | "Ana", "Luis" |
Dicho de otra forma: el parámetro es la etiqueta del hueco y el argumento es lo que metes en él. El parámetro es siempre el mismo; el argumento cambia en cada llamada.
Varios parámetros#
Se separan por comas, tanto al definir como al llamar:
def mostrar_linea_pedido(producto, cantidad, precio):
total = cantidad * precio
print(f"{producto:<12} {cantidad:>3} x {precio:>6.2f} = {total:>7.2f}")
mostrar_linea_pedido("Camiseta", 2, 19.99)
mostrar_linea_pedido("Zapatillas", 1, 49.50)Camiseta 2 x 19.99 = 39.98
Zapatillas 1 x 49.50 = 49.50El orden posicional#
Por defecto, los argumentos se emparejan con los parámetros por su posición: el primero con el primero, el segundo con el segundo. Python no mira los tipos ni intenta adivinar nada.
Si te equivocas de orden, no te avisa de inmediato. Te deja seguir hasta que algo revienta:
mostrar_linea_pedido(2, "Camiseta", 19.99)Traceback (most recent call last):
File "/Users/erwin/curso-python/pedido.py", line 6, in <module>
mostrar_linea_pedido(2, "Camiseta", 19.99)
~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/Users/erwin/curso-python/pedido.py", line 2, in mostrar_linea_pedido
total = cantidad * precio
~~~~~~~~~^~~~~~~~
TypeError: can't multiply sequence by non-int of type 'float'Mira bien ese traceback: tiene dos bloques File. El de abajo señala la línea que ha petado, dentro de la función. El de arriba señala la llamada que provocó el problema. Cuando trabajas con funciones, el traceback se convierte en el recorrido completo desde donde empezó todo hasta donde acabó mal, y esa es justamente su utilidad.
Pasar argumentos por nombre#
Puedes decir explícitamente a qué parámetro va cada valor, escribiendo parametro=valor en la llamada. Así el orden deja de importar:
def registrar_envio(ciudad, urgente, asegurado):
print(f"Envío a {ciudad}. Urgente: {urgente}. Asegurado: {asegurado}.")
registrar_envio("Valencia", True, False)
registrar_envio(ciudad="Valencia", urgente=True, asegurado=False)
registrar_envio(asegurado=False, ciudad="Valencia", urgente=True)Envío a Valencia. Urgente: True. Asegurado: False.
Envío a Valencia. Urgente: True. Asegurado: False.
Envío a Valencia. Urgente: True. Asegurado: False.Las tres llamadas hacen lo mismo, pero no se leen igual. La primera, registrar_envio("Valencia", True, False), obliga a quien la lee a ir a buscar la definición para saber qué significan ese True y ese False. La segunda se explica sola.
Mezclar posicionales y por nombre#
Se pueden combinar, con una regla estricta: los posicionales van siempre primero. En cuanto usas uno por nombre, todos los siguientes tienen que ir también por nombre.
registrar_envio("Valencia", asegurado=False, urgente=True) # válidoAl revés, ni siquiera llega a ejecutarse:
registrar_envio(ciudad="Valencia", True, False) File "/Users/erwin/curso-python/envios.py", line 5
registrar_envio(ciudad="Valencia", True, False)
^
SyntaxError: positional argument follows keyword argumentEl motivo de la regla es fácil de ver: si el primer hueco ya lo has ocupado por nombre, ¿qué posición le tocaría al siguiente argumento suelto? Python prefiere no adivinar.
Cuando faltan o sobran argumentos#
Aquí Python sí es tajante y el mensaje te dice exactamente qué pasa. Partimos de esta función:
def calcular_total(precio, cantidad):
print(precio * cantidad)Qué le puedes pasar a una función#
Cualquier cosa que sea un valor: números, textos, booleanos, listas, tuplas, diccionarios, e incluso el resultado de otra función.
def contar_palabras(frase):
print(len(frase.split()))
def resumir_notas(notas):
print(f"{len(notas)} notas, media {sum(notas) / len(notas):.2f}")
contar_palabras("El pedido llega el martes por la mañana")
resumir_notas([7, 9, 5, 8])8
4 notas, media 7.25