Home
Series About Subscribe
Los argumentos opcionales DEBEN usar palabras clave (Python 3)

Los argumentos opcionales DEBEN usar palabras clave (Python 3)

En este post, repasaremos una historia sencilla de cómo los argumentos opcionales en Python ayudan a los desarrolladores a escribir mejor código.


Imagina que estás desarrollando software para una gran empresa naviera. Y te encargan implementar una función para calcular las tarifas de paso de los barcos según el peso de la carga. Fácil y sencillo:

WEIGHT_RATES = [
    ( 10, 10.55),
    (  5, 5.05),
    (  2, 3.35),
    (  0, 1.25)
]

def calculate_fees(weight):
    if weight < 0:
        raise ValueError("Can't calculate shipping charge of negative weights")
    for min_weight, rate in WEIGHT_RATES:
        if weight > min_weight:
            return weight * rate

Bastante simple.

Pero algún día tu programa funcionará en otro país, digamos, Estados Unidos. Hay un problema — tienes que usar libras en vez de kilogramos para calcular la tarifa. No hay problema, ahí lo tienes:

def calculate_fees(weight, pnds):
    if pnds:
       weight /= 2.2
    if weight < 0:
       raise ValueError("Can't calculate shipping charge of negative weights")
    for min_weight, rate in WEIGHT_RATES:
        if weight > min_weight:
            return weight * rate

Esto se vuelve cada vez más difícil, pero aquí viene otro requisito — según un flag booleano, tienes que lanzar una excepción si el peso supera los 1000 kilogramos para ciertas rutas:

def calculate_fees(weight, pnds, exceed):
    if pnds:
       weight /= 2.2
    if exceed and weight > 1000:
       raise Exception("Weight can't exceed 1000 kg")
    if weight < 0:
       raise ValueError("Can't calculate shipping charge of negative weights")
    for min_weight, rate in WEIGHT_RATES:
        if weight > min_weight:
            return weight * rate

¿Ves el problema? En este ejemplo simplificado, tienes una función con 3 argumentos posicionales, y los dos últimos son del mismo tipo. El usuario final, o tú mismo como desarrollador, puede fácilmente olvidar cuál va primero y confundirlos. Gracias a que son del mismo tipo, el programa en Python no fallará, y obtendrás un error lógico:

calculate_fees(2000, True, False)

o

calculate_fees(2000, False, True)

Puedes usar argumentos con palabra clave y valores por defecto, y es una buena práctica:

def calculate_fees(weight, pnds=False, exceed=False):
    if pnds:
       weight /= 2.2
    if exceed and weight > 1000:
       raise Exception("Weight can't exceed 1000 kg")
    if weight < 0:
       raise ValueError("Can't calculate shipping charge of negative weights")
    for min_weight, rate in WEIGHT_RATES:
        if weight > min_weight:
            return weight * rate

Pero el problema no está resuelto. Para resolverlo, tenemos que obligar al usuario final a usar argumentos con palabra clave de forma explícita. Para hacerlo, hay que añadir un asterisco al principio de la lista de argumentos con palabra clave:

def calculate_fees(weight, *, pnds=False, exceed=False):
    if pnds:
       weight /= 2.2
    if exceed and weight > 1000:
       raise Exception("Weight can't exceed 1000 kg")
    if weight < 0:
       raise ValueError("Can't calculate shipping charge of negative weights")
    for min_weight, rate in WEIGHT_RATES:
        if weight > min_weight:
            return weight * rate

Eso es todo, la próxima vez que llames a esta función obtendrás un error:

>>> calculate_fees(2000, True, False)
TypeError: calculate_fees() takes 1 positional argument but 3 were given

Más información: PEP-3102

Liked this? I publish one deep-dive every week.

Join 4,000+ engineers. No BS.

Get the newsletter

Enjoyed what you just read? Others like these as well:

Python Interview Questions for Beginners (Junior)

Design Patterns Suck

Python Interview Questions for Mid-Level Developers