DEV Community

Cover image for Optional arguments MUST use keywords (Python3)
luminousmen
luminousmen

Posted on • Updated on

Optional arguments MUST use keywords (Python3)

Imagine that you are developing software for a big shipping company(why would you imagine small anyway). And you got a task to create a function for calculating a charge for ships based on their cargo weight. Easy breezy:

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

def shipping_charge(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

Enter fullscreen mode Exit fullscreen mode

Simple enough.
But then one day your program eventually is going to work in another country, say the USA. One problem arises: we need to use pounds instead of kilograms for charging. No problem, here you are:

def shipping_charge(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
Enter fullscreen mode Exit fullscreen mode

This is getting complicated, but then one more requirement - you need to raise an exception if weight exceeds 1000 kilograms for specific directions:

def shipping_charge(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
Enter fullscreen mode Exit fullscreen mode

You see the problem? On this stupid example, you came up to function with 3 positional arguments, two last of them with the same type. The end user, or you as a developer can easily forget which one needs to come first and messed them up. Due to the same type Python program will not fail and you will get a logic error:

shipping_charge(2000, True, False)
Enter fullscreen mode Exit fullscreen mode

or

shipping_charge(2000, False, True)
Enter fullscreen mode Exit fullscreen mode

You can use a keyword arguments with a default values and it's a good practice:

def shipping_charge(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
Enter fullscreen mode Exit fullscreen mode

But the problem is not solved. To solve the problem you need to add one star in the argument list:

def shipping_charge(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
Enter fullscreen mode Exit fullscreen mode

That's it, next time you will call this function you will got an error:

>>>shipping_charge(2000, True, False)
TypeError: shipping_charge() takes 1 positional argument but 3 were given
Enter fullscreen mode Exit fullscreen mode

More info:PEP-3102


Thank you for reading!

Any questions? Leave your comment below to start fantastic discussions!

Check out my blog or come to say hi đź‘‹ on Twitter or subscribe to my telegram channel.
Plan your best!

Top comments (0)