Optional arguments MUST use keywords (Python3)
Tags: python, programming
Published: 2019-01-19 07:57:32

---
title:  Optional arguments MUST use keywords (Python3)
published: true
description: Optional arguments MUST use keywords (Python 3), the quick explanation of part of PEP-3102  
tags: #python #programming
cover_image: https://thepracticaldev.s3.amazonaws.com/i/df3uaf5fln3r5lu8pias.jpg
---


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:

```python
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:

```python
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:

```python
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:

```python
shipping_charge(2000, True, False)
```

or
```python
shipping_charge(2000, False, True)
```

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

```python
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:

```python
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:

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

More info:[PEP-3102](https://www.python.org/dev/peps/pep-3102/)

------

**Thank you for reading!**

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

Check out [my blog](https://luminousmen.com/) or come to say hi 👋 on [Twitter](https://twitter.com/luminousmen) or subscribe to [my telegram channel](https://t.me/iamluminousmen).
Plan your best!