Ir al contenido
wannacode

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))
Salida
8.0

Con tres argumentos funciona. Con dos, el programa se detiene:

Error
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
  1. def guarda la función con el nombre print_header. El nombre apunta a ella.
  2. Una llamada: el nombre apunta a la primera función, y esta imprime «Tienda del barrio».
  3. El segundo def crea una función nueva y hace que el mismo nombre apunte a ella. La primera ya no existe.
  4. La segunda llamada: «Tienda Centro».
  5. 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)
Respuesta

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))
Salida
6.5
8.0

c=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"))
Salida
['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"))
Salida
['pan']
['leche']

Pruébalo

Encuentra el error

El programa no arranca. Python se detiene con un SyntaxError antes de ejecutar una sola línea. ¿En qué línea está el error?

Elige la línea con el error.

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")
Salida
María, noches: 1
Pablo, noches: 3
Lucía, noches: 1
con desayuno
Jorge, noches: 2

Lucí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:

Error
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 que book("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())
Salida
11.0
9.99
0

El 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)
Salida
(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))
Salida
Pan Leche Café
8
Má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 con receipt(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

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.

Llamadas
largest(3, 8)
largest(4, 9, 2)
largest(2.5, 1.5)
Salida
8
9
2.5

2. Nota media. La función average(*grades) devuelve la media de cualquier número de notas, y sin notas devuelve 0.

Llamadas
average(5, 6, 4)
average(6, 5)
average()
Salida
5.0
5.5
0

3. Una línea del recibo. print_line(item, qty) imprime «Café x 2». Haz que la cantidad sea opcional: sin ella, es 1.

Llamadas
print_line("Café", 2)
print_line("Cruasán")
Salida
Café x 2
Cruasán x 1

4. 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.

Llamadas
shipping_cost(62.0)
shipping_cost(30.0)
shipping_cost(30.0, free_from=25)
Salida
0
4.99
0

Test

Ponte a prueba

1. El archivo tiene def total(a, b): y debajo def total(a, b, c):. ¿Qué pasa con total(2, 3)?
2. def total(a, b, c=0): ¿Qué devuelve total(2, 3)?
3. ¿Cómo llamas a def book(name, nights=1, breakfast=False): para que haya desayuno y las noches se queden en 1?
4. ¿Qué es prices dentro de def total(*prices):?
5. ¿Cuál de estos NO ejecuta Python?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·