# Optional arguments MUST use keywords (Python3)

Imagine that you are developing software for the 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

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

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

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)`

or

`shipping_charge(2000, False, True)`

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

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

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

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!