Valores por defecto
En resumen: El valor por defecto de un parámetro se usa cuando no se pasa el argumento; Python tiene además argumentos por nombre, y *args acepta tantos argumentos como quieras.
Problema
Dos productos, tres productos
La caja tiene que sumar los precios de los productos. A veces son dos, a veces tres. La función significa lo mismo en los dos casos: «suma». En Java y C# esto se hace con dos métodos que tienen un mismo nombre y distinto número de parámetros. Pruebas lo mismo:
def total(a, b): return a + b
def total(a, b, c): return a + b + c
print(total(2.5, 4.0, 1.5))print(total(2.5, 4.0))8.0Con tres argumentos funciona. Con dos, el programa se detiene:
TypeError: total() missing 1 required positional argument: 'c'Python dice que a total le falta c. O sea, llama a la función de tres parámetros. ¿Adónde fue la primera?
La idea
Un nombre, una función
En Python, def es una instrucción como cualquier otra. Se ejecuta cuando el programa llega a ella y guarda la función con un nombre. Un segundo def con el mismo nombre guarda una función nueva con ese nombre, y la vieja se pierde. El último def antes de la llamada decide qué función se ejecuta.
Por eso Python no tiene sobrecarga (overloading): dos funciones con un mismo nombre que se diferencian en sus parámetros, como en Java y C#. En su lugar, una sola función puede aceptar un número distinto de argumentos. Verás cómo en las siguientes tarjetas.
def print_header(): print("Tienda del barrio")
print_header()
def print_header(): print("Tienda Centro")
print_header()Paso a paso, en palabras
- def guarda la función con el nombre print_header. El nombre apunta a ella.
- Una llamada: el nombre apunta a la primera función, y esta imprime «Tienda del barrio».
- El segundo def crea una función nueva y hace que el mismo nombre apunte a ella. La primera ya no existe.
- La segunda llamada: «Tienda Centro».
- El nombre es uno solo. El último def al que ha llegado el programa decide qué función se llama.
Pruébalo
¿Qué función?
¿Qué imprimirá el programa?
def describe(x): print(f"entero: {x}")
def describe(x): print(f"decimal: {x}")
describe(5)describe(5.0)def describe ha reemplazado al primero, así que las dos llamadas llegan a «decimal». Python no elige una función por el tipo del argumento: 5 y 5.0 van a la misma función.La idea
Un valor por defecto
Una sola función basta para dos y para tres productos. Dale al tercer parámetro un valor por defecto: se usa cuando no se pasa el argumento.
def total(a, b, c=0): return a + b + c
print(total(2.5, 4.0))print(total(2.5, 4.0, 1.5))6.58.0c=0 significa: si la llamada tiene solo dos argumentos, c es 0. Si tiene tres, c es el tercero.
En Python no se ponen espacios alrededor del = de un valor por defecto: c=0. Así lo dice la guía de estilo PEP 8.
Los parámetros con valor por defecto se escriben después de los que no lo tienen. Los argumentos se asocian a los parámetros por posición, así que los opcionales van al final.
Más precisamente, para curiosos
El valor por defecto se calcula una vez, cuando Python llega al def, no en cada llamada. Para números y texto esto da igual. Pero una lista por defecto es la misma lista para todas las llamadas:
def add_item(item, cart=[]): cart.append(item) return cart
print(add_item("pan"))print(add_item("leche"))['pan']['pan', 'leche']La segunda llamada continúa la lista de la primera. Por eso, para una lista por defecto se escribe None y la lista se crea dentro de la función:
def add_item(item, cart=None): if cart is None: cart = [] cart.append(item) return cart
print(add_item("pan"))print(add_item("leche"))['pan']['leche']Pruébalo
Encuentra el error
SyntaxError antes de ejecutar una sola línea. ¿En qué línea está el error?Elige la línea con el error.
nights=1) va antes del parámetro sin él (name). Python lo prohíbe: «parameter without a default follows parameter with a default». La corrección es def book(name, nights=1):.La idea
Argumentos por nombre
Un hotel toma reservas. Lo más habitual es una noche sin desayuno, así que las dos cosas son valores por defecto:
def book(name, nights=1, breakfast=False): print(f"{name}, noches: {nights}") if breakfast: print(" con desayuno")
book("María")book("Pablo", 3)book("Lucía", breakfast=True)book(nights=2, name="Jorge")María, noches: 1Pablo, noches: 3Lucía, noches: 1 con desayunoJorge, noches: 2Lucía quiere desayuno, pero solo una noche. No hace falta que escribas las noches: breakfast=True pasa el argumento por nombre, directo al parámetro breakfast. Esto se llama argumento por nombre (keyword argument). Con nombres, el orden no importa: Jorge pasa los dos argumentos por nombre, en orden inverso.
El nombre tiene que ser exacto. Un nombre mal escrito no pasa en silencio, sino que detiene el programa:
book("María", night=2)
TypeError: book() got an unexpected keyword argument 'night'Más precisamente, para curiosos
- Después de un argumento por nombre no puede ir un argumento sin nombre:
book(name="María", 3)no arranca («positional argument follows keyword argument»). - Los argumentos por nombre hacen más clara una llamada aunque no te saltes nada:
book("Pablo", nights=3)se lee mejor quebook("Pablo", 3).
La idea
Tantos argumentos como quieras
¿Y si los productos son cinco? ¿Veinte? No escribes un parámetro para cada uno. Dices que la función acepta un número variable de argumentos:
def total(*prices): result = 0 for p in prices: result += p return result
print(total(1.5, 2.0, 3.5, 4.0))print(total(9.99))print(total())11.09.990El asterisco delante del nombre (*prices) significa: «pasa tantos valores como quieras». Dentro de la función llegan como una tupla (tuple): una secuencia como una lista, pero que no se puede modificar. Sin argumentos está vacía.
def show(*prices): print(prices)
show(1.5, 2.0)(1.5, 2.0)Por eso también print imprime tantos valores como le des: es una sola función que acepta un número variable de argumentos.
print("Pan", "Leche", "Café")print(max(3, 8, 2))Pan Leche Café8Más precisamente, para curiosos
- Solo puede haber un parámetro así. Los parámetros que van después solo se pueden pasar por nombre:
def receipt(*prices, currency="€")se llama conreceipt(2.5, 4.0, currency="EUR"). - También existe
**options: reúne los argumentos por nombre en un diccionario. Te lo encontrarás en código ajeno.
Pruébalo
¿Qué falta?
def total(prices):
result = 0
for p in prices:
result += p
return result*prices: el asterisco delante del nombre reúne todos los argumentos.Ejercicio
Una función en lugar de varias
1. El mayor. Escribe una sola función, largest(*numbers), que devuelva el mayor de cualquier cantidad de números.
largest(3, 8)largest(4, 9, 2)largest(2.5, 1.5)892.52. Nota media. La función average(*grades) devuelve la media de cualquier número de notas, y sin notas devuelve 0.
average(5, 6, 4)average(6, 5)average()5.05.503. Una línea del recibo. print_line(item, qty) imprime «Café x 2». Haz que la cantidad sea opcional: sin ella, es 1.
print_line("Café", 2)print_line("Cruasán")Café x 2Cruasán x 14. Envío gratis. shipping_cost(total, free_from=50) devuelve 0 si el pedido llega al menos al umbral y, si no, 4,99 €. El umbral es 50 €, salvo que se pase otro.
shipping_cost(62.0)shipping_cost(30.0)shipping_cost(30.0, free_from=25)04.990Test
Ponte a prueba
Lecciones relacionadas
Sección «Lecciones relacionadas»- Se basa en: Bucles · Listas · Funciones · Parámetros y return
- Continúa en: Builder · Decorator · Composite · Funciones: una tarea, pocos parámetros, sin efectos secundarios ocultos
- Ejercicios sobre el tema: Funciones