Python starred expressions: practical challenges
Tags: python, pythontips
Published: 2020-12-05 20:33:53

As I promised, I'm [continuing my post](https://dev.to/v_it_aly/python-tips-unpack-data-gracefully-4o3o) on how to use starred expressions, this time with more practical and complicated examples.

#### RUNNING AN ONLINE SHOP
Let's write a simple programme that would calculate a discount for online orders. For ordinary purchases, we'll add up all customer's discounts (loyalty programme for regulars, promo codes, etc.). For special offers like a 30% or 50% discount, we'll just choose the biggest discount, otherwise your little shop will go bankrupt :)

The thing is, you don't know how many bonuses a customer might have, but you need to process them all. And that's how we'll do it:
```python
data = [
    ('Abraham Lincoln', 'special', 50, 5, 25, 3, 15, 'address'),
    ('George Washington', 'regular', 5, 5, 'address'),
    ('Thomas Jefferson', 'regular', 10, 3, 'address'),
    ('James Maddison', 'special', 30, 10, 10, 'address')
]

def special_offer(discounts: list) -> int:
    """ We choose the biggest discount for a special offer. """
    return max(discounts)

def regular_offer(discounts: list) -> int:
    """ If there's no special offer, we sum up the discounts. """
    return sum(discounts)

if __name__ == '__main__':
    for line in data:
        customer, tag, *discounts, _ = line
        if tag == 'special':
            percent = special_offer(discounts)
        else:  # regular
            percent = regular_offer(discounts)
        print(f'Customer {customer} is offered a discount of {percent}%')
```
Let's execute the script:
```
Customer Abraham Lincoln is offered a discount of 50%
Customer George Washington is offered a discount of 10%
Customer Thomas Jefferson is offered a discount of 13%
Customer James Maddison is offered a discount of 30%
```
Nice, but we can do better! The interesting thing here is that in a `for` loop we have an implicit assignment, and we don't really need to assign `line` to variables in a separate line. So, let's rework our last chunk a bit:
```python
if __name__ == '__main__':
    for customer, tag, *discounts, _ in data:
        if tag == 'special':
            percent = special_offer(discounts)
        else:  # regular
            percent = regular_offer(discounts)
        print(f'Customer {customer} is offered a discount of {percent}')
```
An implicit tuple assignment means that a row of variables `customer, tag, *discounts` is treated here as a tuple being assigned values, so you may as well type `(customer, tag, *discounts)` and nothing will change. It's just more comfortable not to use `()`. 

Python's [PEP 3132](https://www.python.org/dev/peps/pep-3132/#specification) offers us another example. It's a little abstract, though, but demonstrates the concept:
```python
for a, *b in [(1, 2, 3), (4, 5, 6, 7)]:
    print(b)
```
After executing, you'll get:
```python
[2, 3]
[5, 6, 7]
```

#### SENDING A HOLIDAY CARD
Now, we'd like to send a holiday card to our online shop customers. See how clean our code looks when using `*_` instead of awkward indexes with arbitrary-sized tuples:
```python
data = [
    ('Abraham Lincoln', 'special', 50, 5, 25, 3, 15, 'address'),
    ('George Washington', 'regular', 5, 5, 'address'),
    ('Thomas Jefferson', 'regular', 10, 3, 'address'),
    ('James Maddison', 'special', 30, 10, 10, 'address')
]

if __name__ == '__main__':
    for customer, *_, address in data:
        print(f'A card for {customer} to some {address}')
```

#### DOING BUSINESS RESEARCH
Let's solve another problem. You're a data scientist conducting a research on salaries (or whatever) in local companies. You've got raw data strings containing a company name and impersonated data on each employee's salary there. Since each company has a different number of employees, you'd want to write code that would be able to process them all regardless of the number of the employees.

You can use a string method `.split()`, and extract a company name using `.pop()`:
```python
salaries = 'ImageInc|100000|110000|80000|60000|115000|250000|20000'
salaries = salaries.split('|')
company = salaries.pop(0)
print(company, salaries)
```
You'll get:
```python
ImageInc ['100000', '110000', '80000', '60000', '115000', '250000', '20000']
```
Let's just use starred expressions:
```python
data = 'ImageInc|100000|110000|80000|60000|115000|250000|20000'
company, *salaries = data
print(company, salaries)
```
Something wrong, eh? We forgot to split it, it's a string, so each character was treated as a value. Let's fix it:
```python
data = 'ImageInc|100000|110000|80000|60000|115000|250000|20000'
company, *salaries = data.split('|')  # unpacking a list now
```
We've saved ourselves and our fellow programmers some time. Nice!

#### DAILY STUFF
Starred expressions are something that could be used quite often even in very trivial assignments:
```python
nums = [1, 2, 3, 4]
# first, rest = nums[0], nums[1:]  # the hard way
first, *rest = nums  # the Python way :)
```
See? No need to wonder which index goes where. 

#### SELF-PRACTICE
If you'd like to practice on your own a little, I've got a task for you. You've got some raw data here:
```python
raw_data = [
    (10, 100, 349, 304, 203, 402, 798, 356),
    (465, 1254, 124, 875),
    (312, 46, 25, 96, 564, 183),
    (828, 4723, 7472, 588, 127, 872, 743, 400)
]
```
Using starred expressions, first print the sum of the first values from each tuple in a `raw_data` list. Then, do the same with all values between the first and the last in each tuple.

Now, you're fully ~~starred~~ prepped to use starred expressions! Hope you enjoyed my post! Please don't forget to leave a like if you did :)

If you still feel like learning some more Python tips, check out my [post](https://dev.to/v_it_aly/python-tips-elegant-exception-handling-with-contextlib-suppress-2d0e) about elegant exception handling.