As I promised, I'm continuing my post 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:
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:
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 offers us another example. It's a little abstract, though, but demonstrates the concept:
for a, *b in [(1, 2, 3), (4, 5, 6, 7)]:
print(b)
After executing, you'll get:
[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:
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()
:
salaries = 'ImageInc|100000|110000|80000|60000|115000|250000|20000'
salaries = salaries.split('|')
company = salaries.pop(0)
print(company, salaries)
You'll get:
ImageInc ['100000', '110000', '80000', '60000', '115000', '250000', '20000']
Let's just use starred expressions:
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:
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:
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:
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 about elegant exception handling.
Top comments (0)