Imagine that you are developing software for a large shipping company (why not imagine a small company). And you have the task of creating a function for calculating fees for ships based on their cargo weight. Easy peasy:

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

Simple enough.

But one day your program will eventually work in another country, say, the United States. There's one problem — you have to use pounds instead of kilograms to calculate fees. No problem, there you are:

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

This becomes more and more complicated, but then there is another requirement — you have to raise the exception if the weight exceeds 1000 kilos for specific directions:

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

Do you see the problem? In this dummy example, you get to a function with 3 position arguments, the last two of which have the same type. The end-user or you as a developer can easily forget which one should come first and mess them up. Thanks to the same type, the Python program will not fail and you will get a logical error:

```
calculate_fees(2000, True, False)
```

or

```
calculate_fees(2000, False, True)
```

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

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

But the problem is not solved. To solve the problem, you need to add one asterisk at the beginning of the keyword arguments list:

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

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

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

More info: PEP-3102

Daily dose of