Loss of Words • A Nested Journey (# 1 in The `itertools` Series • `product()`)
Follow Yteria on her troubled journey, explore her unusual world in this first article in The `itertools` Series. Discover `itertools.product()` and `itertools.starmap()`
She slammed the door and leaned against it as if to make sure it stayed closed. Now she was back in her flat, she could pause to catch her breath. But she was still shaking.
Yteria had moved to this neighbourhood a couple of months earlier. It's all she could afford. She'd always been vigilant when out and about, but today, her luck ran out. She was mugged three blocks from home.
The miscreants only managed to steal one word from her. But it was a common word—one that would be expensive to buy again from the word shops.
A year ago, she had lost a silly bet with a friend and had to give up "trepidation". Even that word wasn't cheap in the word shops, and she chose not to buy it back. But the loss of "trepidation" didn't cause her too much trouble.
But this time, she had lost "for". She wouldn't even bother to check how much it costs to replace it. She knew she wouldn't be able to afford it.
Yteria lived in a world a bit different from yours and mine. In her world, words could be gained or lost. And once you lose a word, you can't say it or write it or think it. You know the word is there, but you can't access it.
Yteria made herself a cup of tea. She'd run out of milk, and she definitely didn't fancy a trip to the shops. Not now.
She sat at her desk and pushed the folded paper firmly under the desk's right leg. It still wobbled a bit, but she could live with that. The blanket on the windowsill had slipped off, and a cold draft came in through the gap in the window frame. Never mind. She just wanted to get started with work. The quicker she can earn some more money, the quicker she can find somewhere else to live.
And maybe buy "for" back.
Yteria's Gig for the Local Restaurant
Yteria opened her laptop, wiggled her fingers, and got ready to start coding. The local restaurant needed a small program to create their menu bundles. Tim, the restaurant owner, gave her a list of mains, sides, and drinks, and he wanted to create a menu with all the bundle options.
"Why can't he just tell his customers to pick one of each?" Yteria wondered. But she didn't care. A job is a job. It doesn't pay much, but it's still a job.
Here are the three lists:

She needed to create all the possible bundles that contained one main, one side, and one drink. That's a two-minute job. If only she'd had more of these easy jobs.
But then she paused.
Do you see her problem?
She knew what she needed to do. But she also knew she couldn't do it.
The solution Yteria couldn't use
Here's the code Yteria would have written if she could. I'll write this in a script named using_for.py
:
And this would have done the trick:
Bundles available:
Burger, Salad, Juice
Burger, Salad, Water
Burger, Salad, Wine
Burger, Chips, Juice
Burger, Chips, Water
Burger, Chips, Wine
Burger, Rice, Juice
...
And had Yteria tackled this job in the morning, this is the code she'd have written.
But she lost "for" in the mugging. She couldn't speak the word. She couldn't write the word. She couldn't type the word.
She couldn't write a for
loop—let alone three.
Do you want to join a forum to discuss Python further with other Pythonistas? Upgrade to a paid subscription here on The Python Coding Stack to get exclusive access to The Python Coding Place's members' forum. More Python. More discussions. More fun.
And you'll also be supporting this publication. I put plenty of time and effort into crafting each article. Your support will help me keep this content coming regularly and, importantly, will help keep it free for everyone.
The solution that doesn't use the f-word
Yteria paced around the room, trying to avoid the broken floorboards. If the muggers had to steal a word that's used as a Python keyword, couldn't they have taken "global" instead?
But her friend had mentioned something about some cool tools he'd been using for iteration the other day when they met up. Yteria thought she'd explore this option before giving up.
The itertools
Module
Python is a "batteries included" language. And the itertools
module is one of those many batteries. As it says on the tin, the itertools
module contains itertools—tools for iteration.
And this is the first article in The itertools
Series—I thought long and hard to come up with that series name! But if you're a regular here at The Python Coding Stack, you'll know I don't follow the "normal" rules. So, I'll write the introduction to the series at a later date. When I do, I'll introduce the itertools
module and how it fits with Pythonic looping.
But today, we'll just dive straight in. We'll use two of the tools from itertools
to help Yteria solve her conundrum.
Replacing Nested for
Loops with itertools.product()
Nested for
loops are common in programming. Let's start with a boring one:
These loops go through all possible pairings of the numbers in the outer loop and the ones in the inner loop:
1 101
1 102
1 103
2 101
2 102
2 103
3 101
3 102
3 103
And Python has a tool to simplify this process. You guessed it—it's in itertools
:
Just like all the other tools in itertools
, product()
returns an iterator. Iterators are the natural workhorses of iteration in Python.
Therefore, you'll need to cast the iterator that's returned to a list or a tuple, say, to view its contents:
And here are all the pairs of numbers, the same pairs you got when you used nested for
loops:
[(1, 101), (1, 102), (1, 103),
(2, 101), (2, 102), (2, 103),
(3, 101), (3, 102), (3, 103)]
Instead of casting to another data type, you can unpack the iterator directly using the unpacking operator *
:
Here's the output now:
(1, 101) (1, 102) (1, 103) (2, 101) (2, 102) (2, 103)
(3, 101) (3, 102) (3, 103)
But you really want to replicate the exact same printout you got when you used the nested for
loops, right?
And this gives the required output:
1 101
1 102
1 103
2 101
2 102
2 103
3 101
3 102
3 103
But Yteria won't be able to use this technique to show this output. It uses the for
keyword, which she no longer has access to, unfortunately.
Yteria was playing with this same example I'm showing you before dealing with the more complex menu bundles problem.
It seemed there was no way out. But she persevered:
Woah! What's going on there?
Although map()
is not in itertools
, it comes in useful for certain types of iteration. Normally, you can use a list comprehension or a generator expression if you prefer, which can feel more Pythonic. But both those options need the f-word, which Yteria couldn't use.
Let's break down the arguments you pass to print()
in the code above:
The
map()
callable† iterates throughpairs
and passes each item to the variablepair
in the `lambda` function. Thislambda
function then returns the f-string with the two numbers separated by a space.Since
map()
also returns an iterator, which is iterable, you can unpack it directly in theprint()
call using the unpacking operator*
, as you did earlier with the iterator returned byproduct()
.Finally, by default
print()
uses a space to separate its arguments. But you change this separator to the newline character"\n"
using thesep
keyword argument.
[† I'm being a bit pedantic by calling map()
a callable. You'll often hear it referred to as a function. It looks like a function. You use it like a function. But map
is a class. And therefore, map()
creates an instance of the map
class. But go ahead and call it a function if you want. It's OK. That's duck typing for you!]
Here's the output:
1 101
1 102
1 103
2 101
2 102
2 103
3 101
3 102
3 103
A lot is happening in those few lines of code. You can spend some time digesting them and experimenting with them on your computer. You'll reuse these tricks again and again in the rest of this tutorial.
A reminder that I'm using this solution to print out the value—a solution that scores low on readability—because Yteria got mugged and lost the word "for". If she hadn't, the previous version that uses a for
loop to iterate through pairs
would be preferable.
Yteria's Menu Bundle Solution That Doesn't Use the F-Word
Yteria was ready to finish her menu bundle code. As a reminder, here's the code she would have liked to write but couldn't:
The first challenge was to replace the nested for
loops. There are three levels of nesting on this occasion. But product()
can deal with as many levels of nesting as you need. I'll use a new script named without_f__.py
:
Recall that product()
returns an iterator. You can unpack bundle_options
to see what's in it:
The truncated output, which I split into several lines below, looks like this:
('Burger', 'Salad', 'Juice') ('Burger', 'Salad', 'Water')
('Burger', 'Salad', 'Wine') ('Burger', 'Chips', 'Juice')
('Burger', 'Chips', 'Water') ('Burger', 'Chips', 'Wine')
('Burger', 'Rice', 'Juice') ('Burger', 'Rice', 'Water')
...
('Salmon', 'Rice', 'Water') ('Salmon', 'Rice', 'Wine')
Therefore, the iterator bundle_options
, which is the iterator that product()
returned, yields tuples. Each one of these tuples contains three strings.
But Yteria didn't want to print out tuples showing strings. She wanted the simpler output the restaurant needed. She could rely on map()
again, but in this case, she could use the string method .join()
:
In this case, map()
iterates through bundle_options
and passes each item yielded by this iterator to the method ", ".join
.
For example, the first item yielded by bundle_options
is ('Burger', 'Salad', 'Juice')
. Therefore, the first element yielded by map()
is the return value of ", ".join(('Burger', 'Salad', 'Juice'))
. This returns the string 'Burger, Salad, Juice'
.
Yteria still needed to use the keyword argument sep="\n"
in print()
.
If you're following along with Yteria, remember that you need to comment out or delete the temporary line you added in the previous step when you unpacked bundle_options
in a print()
call. Iterators can only be used once. So, if you unpack bundle_options
, you can't use it again.
Here's the truncated output from Yteria's code:
Bundles available:
Burger, Salad, Juice
Burger, Salad, Water
Burger, Salad, Wine
Burger, Chips, Juice
Burger, Chips, Water
Burger, Chips, Wine
Burger, Rice, Juice
...
Job done. Yteria didn't let the missing f-word thwart her from completing the task. She desperately needed to get paid for this job.
Let's Compare the Two Solutions
Which solution is better, the one with the nested for
loops in using_for.py
or Yteria's version without_f__.py
?
Better is a subjective term. Many Python programmers may consider using itertools.product()
more Pythonic than nested for
loops. Using product()
is more concise and avoids nesting. It makes your intent clear as long as those reading your code are familiar with product()
. Efficiency is another reason you may want to use product()
. You'll explore this shortly.
However, printing out the results using map()
and .join()
isn't very readable. A Pythonic solution would likely use product()
but then use a simple for
loop to print out the menu bundles.
How about speed, then? Let's compare them.
To avoid printing out lots of output, I'll modify the code so that the solutions each produce a list of tuples with the food triplets. I'll enclose the solutions in functions so we can time them.
Let's start with the nested for
loops solution:
This function returns a list of tuples:
[('Burger', 'Salad', 'Juice'), ('Burger', 'Salad', 'Water'),
('Burger', 'Salad', 'Wine'), ('Burger', 'Chips', 'Juice'),
('Burger', 'Chips', 'Water'), ('Burger', 'Chips', 'Wine'),
('Burger', 'Rice', 'Juice'), ('Burger', 'Rice', 'Water'),
...
('Salmon', 'Rice', 'Water'), ('Salmon', 'Rice', 'Wine')]
And here's the equivalent version using itertools.product()
:
To make this a fair comparison, you'll need to cast the iterator returned by product()
to a list. Rather than printing out the result, you can confirm that the two functions produce identical outputs by using the equality operator ==
in the print()
call at the bottom. This prints True
, confirming the functions return identical lists.
One more thing before timing these alternatives. You may be currently shouting at your screen, telling me that there's another solution to the nested loops that's more Pythonic: list comprehensions. Recall that Yteria can't use list comprehensions either, as they need the word she lost. But let's add it anyway to this race:
The three functions return identical lists. The print()
call at the bottom displays True
.
You can now time these three solutions using the timeit
module. A reminder that the timings on your computer may be different to the ones shown here, and you may need to reduce the number of repetitions if your code takes too long:
You repeat each function five million times. And here are the results on my computer:
Nested Loops:
5.533897084000273
List comprehensions:
4.71960929099987
itertools.product():
3.2513274579996505
List comprehensions are faster than nested for
loops.
But itertools.product()
is even faster. Like all tools in the itertools
module, product()
performs the required task using efficient algorithms at the C level. This approach makes it faster than nested loops. And since it returns an iterator, all operations are performed lazily, ensuring you don't have copies of your data that require memory.
Yteria stumbled on a solution that was more efficient than her original plan!
Tim, the Restaurant Owner, Changed His Requirements
Yteria was about to email Tim, the restaurant owner. But she found an email from him in her inbox. He had made a mistake in his brief. He also wanted to include the prices of each menu bundle. Now, this made more sense. That's why he didn't just want to list the mains, sides, and drinks and let customers pick and mix as they please. He wanted them to see the price of their chosen bundle, too.
Here's the data Tim sent:
They're the same food items, but now each item is a tuple with the name of the food item and its price.
You can have fun writing the for
loop solution for this. Yteria didn't have this option. But now that she had spent a bit of time finding the solution to Tim's previous—and simpler—request, she felt she could tackle this one, too.
No nested for
loops, but she can use itertools.product()
again:
The last line is temporary. You'll need to remove it later. But it's useful to see what the iterator bundle_options
yields:
(('Burger', 4.5), ('Salad', 3.3), ('Juice', 2.5))
(('Burger', 4.5), ('Salad', 3.3), ('Water', 2.25))
(('Burger', 4.5), ('Salad', 3.3), ('Wine', 4.95))
(('Burger', 4.5), ('Chips', 4), ('Juice', 2.5))
(('Burger', 4.5), ('Chips', 4), ('Water', 2.25))
...
Each line in the output shows an item yielded by the iterator bundle_options
. Each item is a tuple containing three tuples. These inner tuples each contain two items: the name and the price of a food item.
Let's just consider the first item yielded by bundle_options
:
(('Burger', 4.5), ('Salad', 3.3), ('Juice', 2.5))
Yteria needed to take the first item from each inner tuple and combine them into one string, such as "Burger, Salad, Juice"
. But she also needed to take the second item from each tuple and add them to get the total price for the bundle.
Yteria's head was hurting, and she was juggling all these levels of nesting in her head. She opened a REPL and started testing with just this first item at first:
She could unpack these into three variables:
Next, she wanted to construct the string to display the bundle and price. First, she wanted to make sure she could create a string with the three food items:
Great. Now, Yteria could add the bundle's total price to the same f-string:
Yteria had plenty of experience displaying floats in f-strings. So, she added the required format specifier to ensure the price is always displayed with two digits after the decimal point and with a width of five characters. The five characters are sufficient to fit two digits for the dollar amount, two digits for the cents amount, and one digit for the decimal point:
And now for the harder part of the formatting. She wanted to put a space between the end of the last item name and the price. But she wanted this space to be consistent with whatever menu items were listed. Different items have different word lengths, of course!
She wanted to use the :30
width specifier in the f-string, but the three food items all had their own f-string placeholders { }
. She couldn't just add the :30
width specifier to any of these.
No worries, Yteria decided to enclose the three words representing the food items into their own f-string. Yes, f-strings can be nested within other f-strings:
The string containing the three food names and the commas separating them is now set to have a minimum width of 30 characters.
Yteria chose to use single quotes for the inner f-string for readability. However, she could have used double quotes, too (in recent Python versions). This works, but it's hard to read. Yteria thought she could make this mammoth expression a bit more readable by using a template and .format
:
The template is just a string containing the curly brace placeholders and the format specifiers. The first placeholder, {:30}
, represents the string with the three food item names. This is the string that has a minimum width of 30 characters. The second placeholder, {:5.2f}
, represents the price.
The .format()
method then accepts two arguments. The first argument represents the first placeholder, and the second argument…you guessed it, yes!
That's one problem solved.
Applying this exploratory work to the whole bundle_options
iterator
Time to combine all these steps into a call to map()
? In the earlier examples, map()
came to the rescue to create the strings to display.
Yteria attempted to combine the exploratory steps from the REPL session into a single map()
call in her code. But beware—this attempt failed:
Remember to comment out or delete the line that unpacks and prints bundle_options
that you had earlier in your code.
Yteria was trying to pass each item from bundle_options
to the lambda
function. The lambda
function returns the string Yteria had carefully constructed in her exploratory work.
But she got this error:
Traceback (most recent call last):
...
print(*bundle_totals, sep="\n")
~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: <lambda>() missing 2 required positional arguments:
'side' and 'drink'
To understand this error message, we need to remind ourselves what bundle_options
looks like (when you unpack it):
(('Burger', 4.5), ('Salad', 3.3), ('Juice', 2.5))
(('Burger', 4.5), ('Salad', 3.3), ('Water', 2.25))
(('Burger', 4.5), ('Salad', 3.3), ('Wine', 4.95))
(('Burger', 4.5), ('Chips', 4), ('Juice', 2.5))
(('Burger', 4.5), ('Chips', 4), ('Water', 2.25))
...
Each item yielded by bundle_option
is a tuple that contains three further tuples. Since the lambda
function has three parameters, main
, side
, and drink
, the entire tuple—the tuple containing three inner tuples—is assigned to main
. But then there's nothing left for side
and drink
, which are required arguments. That's why the error message complains about these two positional arguments but not the first one.
Yteria considered the option of re-writing the already complicated expression that generates the string without the three separate parameters main
, side
, and drink
. The lambda
function would receive just one argument in this case. And Yteria would have to extract the main, side, and drink manually in the lambda
function's return statement—the part after the colon on the lambda
function.
If she didn't have other options, she'd have tried this, knowing this bit of code would become even less readable. I'll show this version in an appendix for those interested, but I won't pollute the main article with that version.
Instead, Yteria reached into her memory banks for something else that was useful in this case. Conceptually, she wanted to unpack each tuple yielded by bundle_options
before passing it to the lambda
function. After all, this is what she did in the REPL session with these lines:
But is it possible to unpack the three-item tuple within map()
before passing it to the lambda
function? No, map()
can't do that…
But itertools.starmap()
can. That's why it's called starmap()
. It's like map()
but with the star operator *
, which is the unpacking operator in this context.
Yteria replaced map()
with itertools.starmap()
in her code:
She crossed her fingers, ran the code, and…
Burger, Salad, Juice $10.30
Burger, Salad, Water $10.05
Burger, Salad, Wine $12.75
Burger, Chips, Juice $11.00
Burger, Chips, Water $10.75
Burger, Chips, Wine $13.45
Burger, Rice, Juice $11.00
Burger, Rice, Water $10.75
Burger, Rice, Wine $13.45
Pasta, Salad, Juice $10.00
Pasta, Salad, Water $ 9.75
Pasta, Salad, Wine $12.45
Pasta, Chips, Juice $10.70
Pasta, Chips, Water $10.45
Pasta, Chips, Wine $13.15
Pasta, Rice, Juice $10.70
Pasta, Rice, Water $10.45
Pasta, Rice, Wine $13.15
Salmon, Salad, Juice $11.15
Salmon, Salad, Water $10.90
Salmon, Salad, Wine $13.60
Salmon, Chips, Juice $11.85
Salmon, Chips, Water $11.60
Salmon, Chips, Wine $14.30
Salmon, Rice, Juice $11.85
Salmon, Rice, Water $11.60
Salmon, Rice, Wine $14.30
Hurray, it works!
Until Next Time…
Yteria smiled for the first time since her misadventure earlier in the day. She may have lost an important word to the local petty criminals. But even though her coding session took quite a while longer than the couple of minutes she had originally planned, she got there in the end.
And she also gained an appreciation for the itertools
module. Until she finds a way to recover "for", she may need to rely on itertools
quite a bit.
Yteria is off to rest now. But you'll meet her again soon. The itertools
Series here on The Python Coding Stack has only just started…
Code in this article uses Python 3.13
Story inspiration: Il-Fabbrika tal-Kliem
The code images used in this article are created using Snappify. [Affiliate link]
You can also support this publication by making a one-off contribution of any amount you wish.
Appendix: Using map()
Instead of itertools.starmap()
I'll post this without too much explanation. If Yteria didn't know about itertools.starmap()
and had to use map()
, she'd have written this code:
Even less readable than the starmap()
version!
For more Python resources, you can also visit Real Python—you may even stumble on one of my own articles or courses there!
Also, are you interested in technical writing? You’d like to make your own writing more narrative, more engaging, more memorable? Have a look at Breaking the Rules.
And you can find out more about me at stephengruppetta.com
Further reading related to this article’s topic:
A One-Way Stream of Data • Iterators in Python (Data Structure Categories #6)
Iterable: Python's Stepping Stones (Data Structure Categories #1)
The Curious Little Shop at The End of My Street • Python's f-strings
Iterators and Iterables in Python: Run Efficient Iterations – Real Python
Appendix: Code Blocks
Code Block #1
mains = ["Burger", "Pasta", "Salmon"]
sides = ["Salad", "Chips", "Rice"]
drinks = ["Juice", "Water", "Wine"]
Code Block #2
# using_for.py
mains = ["Burger", "Pasta", "Salmon"]
sides = ["Salad", "Chips", "Rice"]
drinks = ["Juice", "Water", "Wine"]
print("Bundles available:")
for main in mains:
for side in sides:
for drink in drinks:
print(f"{main}, {side}, {drink}")
Code Block #3
for number in [1, 2, 3]:
for another_number in [101, 102, 103]:
print(number, another_number)
Code Block #4
import itertools
pairs = itertools.product([1, 2, 3], [101, 102, 103])
Code Block #5
import itertools
pairs = itertools.product([1, 2, 3], [101, 102, 103])
print(list(pairs))
Code Block #6
import itertools
pairs = itertools.product([1, 2, 3], [101, 102, 103])
print(*pairs)
Code Block #7
import itertools
pairs = itertools.product([1, 2, 3], [101, 102, 103])
for first, second in pairs:
print(first, second)
Code Block #8
import itertools
pairs = itertools.product([1, 2, 3], [101, 102, 103])
print(
*map(
lambda pair: f"{pair[0]} {pair[1]}",
pairs,
),
sep="\n"
)
Code Block #9
# using_for.py
mains = ["Burger", "Pasta", "Salmon"]
sides = ["Salad", "Chips", "Rice"]
drinks = ["Juice", "Water", "Wine"]
print("Bundles available:")
for main in mains:
for side in sides:
for drink in drinks:
print(f"{main}, {side}, {drink}")
Code Block #10
# without_f__.py
import itertools
mains = ["Burger", "Pasta", "Salmon"]
sides = ["Salad", "Chips", "Rice"]
drinks = ["Juice", "Water", "Wine"]
bundle_options = itertools.product(
mains,
sides,
drinks,
)
Code Block #11
# without_f__.py
# ...
print(*bundle_options)
Code Block #12
# without_f__.py
import itertools
mains = ["Burger", "Pasta", "Salmon"]
sides = ["Salad", "Chips", "Rice"]
drinks = ["Juice", "Water", "Wine"]
bundle_options = itertools.product(
mains,
sides,
drinks,
)
# print(*bundle_options) <-- You need to remove this line!
print("Bundles available:")
print(
*map(
", ".join,
bundle_options,
),
sep="\n",
)
Code Block #13
mains = ["Burger", "Pasta", "Salmon"]
sides = ["Salad", "Chips", "Rice"]
drinks = ["Juice", "Water", "Wine"]
def using_nested_loops():
output = []
for main in mains:
for side in sides:
for drink in drinks:
output.append((main, side, drink))
return output
print(using_nested_loops())
Code Block #14
import itertools
mains = ["Burger", "Pasta", "Salmon"]
sides = ["Salad", "Chips", "Rice"]
drinks = ["Juice", "Water", "Wine"]
def using_nested_loops():
# ...
def using_product():
return list(
itertools.product(mains, sides, drinks)
)
print(
using_nested_loops()
== using_product()
)
Code Block #15
import itertools
mains = ["Burger", "Pasta", "Salmon"]
sides = ["Salad", "Chips", "Rice"]
drinks = ["Juice", "Water", "Wine"]
def using_nested_loops():
# ...
def using_comprehension():
return [
(main, side, drink)
for main in mains
for side in sides
for drink in drinks
]
def using_product():
# ...
print(
using_nested_loops()
== using_comprehension()
== using_product()
)
Code Block #16
import itertools
import timeit
# ...
repeats = 5_000_000
print("Nested Loops:")
print(
timeit.timeit(
"using_nested_loops()",
number=repeats,
globals=globals(),
)
)
print("List comprehensions:")
print(
timeit.timeit(
"using_comprehension()",
number=repeats,
globals=globals(),
)
)
print("itertools.product():")
print(
timeit.timeit(
"using_product()",
number=repeats,
globals=globals(),
)
)
Code Block #17
mains = [("Burger", 4.5), ("Pasta", 4.2), ("Salmon", 5.35)]
sides = [("Salad", 3.3), ("Chips", 4), ("Rice", 4)]
drinks = [("Juice", 2.5), ("Water", 2.25), ("Wine", 4.95)]
Code Block #18
# with_prices.py
import itertools
mains = [("Burger", 4.5), ("Pasta", 4.2), ("Salmon", 5.35)]
sides = [("Salad", 3.3), ("Chips", 4), ("Rice", 4)]
drinks = [("Juice", 2.5), ("Water", 2.25), ("Wine", 4.95)]
bundle_options = itertools.product(
mains,
sides,
drinks,
)
print(*bundle_options, sep="\n")
Code Block #19
test_item = (('Burger', 4.5), ('Salad', 3.3), ('Juice', 2.5))
Code Block #20
main, side, drink = test_item
main
# ('Burger', 4.5)
side
# ('Salad', 3.3)
drink
# ('Juice', 2.5)
Code Block #21
f"{main[0]}, {side[0]}, {drink[0]}"
# 'Burger, Salad, Juice'
Code Block #22
f"{main[0]}, {side[0]}, {drink[0]} ${main[1] + side[1] + drink[1]}"
# 'Burger, Salad, Juice $10.3'
Code Block #23
f"{main[0]}, {side[0]}, {drink[0]} ${main[1] + side[1] + drink[1]:5.2f}"
# 'Burger, Salad, Juice $10.30'
Code Block #24
f"{f'{main[0]}, {side[0]}, {drink[0]}':30} ${main[1] + side[1] + drink[1]:5.2f}"
# 'Burger, Salad, Juice $10.30'
Code Block #25
format_template = "{:30} ${:5.2f}"
format_template.format(
f"{main[0]}, {side[0]}, {drink[0]}",
main[1] + side[1] + drink[1]
)
# 'Burger, Salad, Juice $10.30'
Code Block #26
# with_prices.py
import itertools
mains = [("Burger", 4.5), ("Pasta", 4.2), ("Salmon", 5.35)]
sides = [("Salad", 3.3), ("Chips", 4), ("Rice", 4)]
drinks = [("Juice", 2.5), ("Water", 2.25), ("Wine", 4.95)]
bundle_options = itertools.product(
mains,
sides,
drinks,
)
# print(*bundle_options, sep="\n") <-- remove this line!
format_template = "{:30} ${:5.2f}"
bundle_totals = map(
lambda main, side, drink: format_template.format(
f"{main[0]}, {side[0]}, {drink[0]}",
main[1] + side[1] + drink[1]
),
bundle_options,
)
print(*bundle_totals, sep="\n")
Code Block #27
test_item = (('Burger', 4.5), ('Salad', 3.3), ('Juice', 2.5))
main, side, drink = test_item
Code Block #28
# with_prices.py
import itertools
mains = [("Burger", 4.5), ("Pasta", 4.2), ("Salmon", 5.35)]
sides = [("Salad", 3.3), ("Chips", 4), ("Rice", 4)]
drinks = [("Juice", 2.5), ("Water", 2.25), ("Wine", 4.95)]
bundle_options = itertools.product(
mains,
sides,
drinks,
)
# print(*bundle_options, sep="\n") <-- remove this line!
format_template = "{:30} ${:5.2f}"
bundle_totals = itertools.starmap(
lambda main, side, drink: format_template.format(
f"{main[0]}, {side[0]}, {drink[0]}",
main[1] + side[1] + drink[1]
),
bundle_options,
)
print(*bundle_totals, sep="\n")
Code Block #29
# with_prices.py
# ...
format_template = "{:30} ${:5.2f}"
bundle_totals = map(
lambda item: format_template.format(
f"{item[0][0]}, {item[1][0]}, {item[2][0]}",
item[0][1] + item[1][1] + item[2][1]
),
bundle_options,
)
# ...
For more Python resources, you can also visit Real Python—you may even stumble on one of my own articles or courses there!
Also, are you interested in technical writing? You’d like to make your own writing more narrative, more engaging, more memorable? Have a look at Breaking the Rules.
And you can find out more about me at stephengruppetta.com
Have you thought of wriitng a book out of this single article? I mean this is unnecessary so long that i have to stop readhing after first paragraph. What makes you think adding that poor girl in your story will make this article viral? I am so annoyed that i had to write this negative comment on this never version of Bible that you have written. Both have same similarities: no one reads them
On second thought, loved the core content. Keep publishing (: