Python Module 10 – Iterators, generators and functional tools
Built-in functions every Python coder should know
Use any, all, sum, min, max, sorted, next and zip with key=, default= and strict=True, and find every other built-in with dir(builtins).
What you will learn
- Use any, all, sum, min, max and sorted on any iterable, and reversed() on sequences
- Apply the key= and default= arguments, and strict=True on zip() and map()
- Predict what built-ins return on empty input, ties, NaN and halves
- Combine built-ins such as next(), enumerate() and zip() instead of writing loops
- Discover built-ins with dir(builtins) and the documentation
Before you start
What you’ll learn · Before you start
What you will learn
- Use any, all, sum, min, max and sorted on any iterable, and reversed() on sequences
- Apply the key= and default= arguments, and strict=True on zip() and map()
- Predict what built-ins return on empty input, ties, NaN and halves
- Combine built-ins such as next(), enumerate() and zip() instead of writing loops
- Discover built-ins with dir(builtins) and the documentation
Before you start
On this page
A sign-up form with four checks, four students and their ages, two lists that should have the same length: each of
these needs a loop, and Python ships each loop as one call. The documentation lists 71
built-in function: A function Python provides in every module without an import, such as len(), sum() or zip(). Built-ins live in the builtins module, and dir(builtins) lists them with the built-in exceptions and constants., from abs() to zip(), and none of them needs an import:
they live in the builtins module, which every module can see.
A dozen of them do most of the everyday work. any() and all() answer a yes-or-no question about a whole
iterable, sum(), min() and max() reduce it to one value, sorted() and reversed() reorder it, enumerate()
and zip() walk through it, and next() takes one item. Three keyword arguments make them flexible: key=,
default= and strict=True.
any() and all() stop at the first item that settles the answer
The form below has four checks, and the code must say whether every one passed and whether any did:
form = {"name": "Asha", "email": "asha@example.com", "age": "17", "pin": "56001"}
checks = [
("name given", lambda f: bool(f["name"].strip())),
("email has @", lambda f: "@" in f["email"]),
("age is 18+", lambda f: int(f["age"]) >= 18),
("pin has 6 digits", lambda f: len(f["pin"]) == 6 and f["pin"].isdigit()),
]
print("all pass:", all(test(form) for _, test in checks))
print("any pass:", any(test(form) for _, test in checks))
print("failed:", [name for name, test in checks if not test(form)])
calls = 0
def counted(test):
def run(f):
global calls
calls += 1
return test(f)
return run
all(counted(test)(form) for _, test in checks)
print("all() ran", calls, "of", len(checks), "checks before it knew") Output
all pass: False any pass: True failed: ['age is 18+', 'pin has 6 digits'] all() ran 3 of 4 checks before it knew
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 form_checks.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
all() is true only if every check passed, and any() if at least one did. Both take a generator expression, so
each check runs only when it is needed, and both short-circuiting: Stopping an and or an or as soon as its answer is known, so the operand on the right is never evaluated. In 0 and 1 / 0 the division never runs. More in “Booleans, None, truthiness and comparisons” at the first item that settles
the answer. Step through all() over the four checks:
The drawing shows the whole scene; its 5 steps are listed below.
Every step as text
- The first check. all() asks the generator expression for its first value, so the first check runs. The name Asha is not blank, so it gives True and all() goes on.
- The second check. The second check runs only now. asha@example.com contains @, so it gives True too, and all() asks for the next value.
- A false check. int("17") >= 18 is False. One false value settles the whole answer, so all() stops asking for more.
- The answer. all() returns False. The pin check never ran, because the generator never had to make its value, which is why the program counted 3 of 4 checks.
- any() on the same form. any() asks the other question. The first check already gives True, so any() returns True after one check and runs none of the others.
all() ran three of the four checks, as the last line printed: the third failed, and nothing after it could change
the result. To report which checks failed, the comprehension in the third line runs every check instead. The diagram
shows both rules, and what each one returns when no item is left:
How any() and all() decide
Text description of the diagram
The diagram has two rows, any(items) above and all(items) below. Each row starts with the step "take the next item".
- any(): if the item is false, it goes on to the next item. At the first true item it returns True at once. When no item is left, it returns False.
- all(): if the item is true, it goes on to the next item. At the first false item it returns False at once. When no item is left, it returns True.
Both stop at the first item that settles the answer, so the items after it are never read, or computed when they come from a generator. With no items at all, any() gives False and all() gives True.
Checkpoint
Check: any() and all() stop early
min(), max() and sum() reduce many items to one value
Four students and their ages: who is the youngest, who is the oldest, and what is the smallest age?
students = [("Ravi", 19), ("Meera", 17), ("Arjun", 18), ("Zoya", 17)]
print(min(students, key=lambda s: s[1])) # the first of the youngest wins a tie
print(max(students, key=lambda s: s[1]))
print(min(s[1] for s in students)) # just the smallest age
print(max([], default="no students")) # empty input needs a default
print(min(4, 9, 2), max("banana")) # several arguments, or one iterable Output
('Meera', 17)
('Ravi', 19)
17
no students
2 n
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 youngest.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
key= works as in sorting: Python calls the key function: A function that sorted(), list.sort(), min() and max() call once for every item; they then compare its results instead of the items. key=len compares the lengths. More in “Lambdas and higher-order functions” on each item and compares
the results, but returns the item itself, so the youngest student comes back as a whole tuple. Meera and Zoya are
both 17, and min() returned Meera. Step through that first call:
The drawing shows the whole scene; its 5 steps are listed below.
Every step as text
- Ravi first. min() calls the key on the first student and gets 19. With nothing to compare yet, Ravi is the youngest so far.
- Meera is younger. The key gives 17 for Meera, which is smaller than 19, so Meera becomes the youngest so far.
- Arjun is not. Arjun's key is 18, which is not smaller than 17, so Meera stays the youngest so far.
- A tie. Zoya's key is 17 as well. It is equal to Meera's, not smaller, so Meera stays. Of several equal items, min() keeps the first one it met.
- The answer. No student is left. min() returns the item it kept, ('Meera', 17), not the key 17, and max() works the same way with the largest key.
Of several equal items, both functions return the first one they meet. An empty input raises ValueError unless
default= gives an answer to return instead. Both also accept several arguments, min(4, 9, 2), and a string is an
iterable of its characters, so max("banana") is "n".
sum(iterable, start) adds the items to start, which is 0 unless you give another value, here 10 bonus marks:
import math
marks = [72, 85, 91]
print(sum(marks), sum(marks, start=10)) # start is added to the total
prices = [0.1] * 10
print(sum(prices), math.fsum(prices))
words = ["learn", "python", "daily"]
try:
sum(words, "")
except TypeError as e:
print("TypeError:", e)
print("-".join(words)) Output
248 258 1.0 1.0 TypeError: sum() can't sum strings [use ''.join(seq) instead] learn-python-daily
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 sum_start.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
Version note
Since Python 3.12, sum() adds floats with a more accurate algorithm, which is why ten times 0.1 now gives exactly
1.0; math.fsum() is still the tool for the most accurate float total.
For strings, sum() refuses outright and its error message names the right tool: "".join(), which builds the
result in one step.
Checkpoint
Check: min(), max() and sum()
zip() and map() drop what does not pair, unless strict=True
Three names and two marks: the mark of the third student is missing.
names = ["Asha", "Ravi", "Meera"]
marks = [91, 78] # one mark is missing
print(list(zip(names, marks))) # silently drops Meera
try:
list(zip(names, marks, strict=True))
except ValueError as e:
print("zip:", e)
print(list(map(lambda n, m: f"{n}: {m}", names, marks)))
try:
list(map(lambda n, m: f"{n}: {m}", names, marks, strict=True)) # new in Python 3.14
except ValueError as e:
print("map:", e) Output
[('Asha', 91), ('Ravi', 78)]
zip: zip() argument 2 is shorter than argument 1
['Asha: 91', 'Ravi: 78']
map: map() argument 2 is shorter than argument 1
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 strict_mismatch.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
zip() stops at its shortest input without a word, so Meera, whose mark is missing, simply disappears from the
pairs. strict=True turns that silent loss into a ValueError that names the shorter argument. map() with several
iterables stops early in the same silent way, and since Python 3.14 it accepts the same strict=True. Step through a
strict map() and watch both flags:
Program · strict_map.py
def label(name, mark):
return f"{name}: {mark}"
names = ["Asha", "Ravi", "Meera"]
marks = [91, 78]
for line in map(label, names, marks, strict=True):
print(line) Variables
- changed in this step
- passed by the loop
- read next
Printed so far
Nothing printed yetAsha: 91 Ravi: 78 Error ValueError: map() argument 2 is shorter than argument 1
Every step was recorded from a run with Python 3.14.8 on macOS 26 arm64.
The drawing shows the variables when the program ends, and the program's 9 steps are listed below.
Change the program and run it here. Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
Every step as text
- Start. No line has run yet, so there are no variables. Python starts with line 1.
- Line 1.
def label(name, mark):makes the functionlabel. Its body runs only when it is called. - Line 5.
names = ["Asha", "Ravi", "Meera"]makesnamesa list of 3 items. - Line 6.
marks = [91, 78]makesmarksa list of 2 items. - Line 7.
for line in map(label, names, marks, strict=True):starts:lineis'Asha: 91'. map() read one item from each list and called label() with them. Both flags have moved to position 1. - Line 8.
print(line)printsAsha: 91. - Line 7.
for line in map(label, names, marks, strict=True):goes round again:lineis'Ravi: 78'. Ravi and 78 make the second pair. Both flags are at position 2 now; names still has Meera, and marks has nothing left. - Line 8.
print(line)printsRavi: 78. - Line 7.
for line in map(label, names, marks, strict=True):stops the program withValueError: map() argument 2 is shorter than argument 1. Key point map() read Meera, then asked marks for a third mark and found none, so strict=True raised ValueError. The two lines before it were printed first, because map() finds the shorter list only at its end.
The lines for Asha and Ravi were printed before the error, because map() notices the missing mark only when it asks
for it. When nothing may happen before the check, build the whole result first and use it afterwards.
Version note
zip() gained strict in Python 3.10 (PEP 618), and map() in Python 3.14.
Checkpoint
Check: zip(), map() and strict=True
A dozen built-ins cover most loops, and dir(builtins) lists the rest
A loop that answers one question about a whole iterable can usually be one call. The table pairs each everyday job with the built-in for it:
| You want | Built-in | Note |
|---|---|---|
| Whether every item passes | all() |
Stops at the first failure |
| Whether some item passes | any() |
Stops at the first success |
| The first matching item | next() with a generator and a default |
Stops at the first match |
| A total | sum() |
math.fsum() for the most accurate float total |
| The smallest or largest | min(), max() with key= and default= |
Ties go to the first item |
| A sorted copy | sorted() with key= and reverse=True |
Works on any iterable |
| The items backwards | reversed() |
Needs a sequence, not a generator |
| Positions with items | enumerate() with start=1 |
Counting from 1 for people |
| Items side by side | zip() with strict=True |
Silent truncation otherwise |
| Quotient and remainder | divmod() |
Rounds the quotient down |
The other built-ins are one line away. dir(builtins) lists everything that a module can use without an import:
import builtins
import inspect
names = [n for n in dir(builtins) if not n.startswith("_")]
exceptions = [n for n in names if inspect.isclass(getattr(builtins, n)) and issubclass(getattr(builtins, n), BaseException)]
lower = [n for n in names if n[0].islower()]
print(len(names), "public names;", len(exceptions), "of them are exceptions and warnings")
print(len(lower), "lower-case names, from", lower[0], "to", lower[-1])
print("some types among them:", [n for n in lower if inspect.isclass(getattr(builtins, n))][:8])
print("number helpers:", divmod(17, 5), abs(-3), pow(2, 10), pow(3, -1, 7), round(3.14159, 2))
print("text helpers:", ord("A"), chr(8377), hex(255), bin(5), format(1234567, ",")) Output
150 public names; 70 of them are exceptions and warnings 75 lower-case names, from abs to zip some types among them: ['bool', 'bytearray', 'bytes', 'classmethod', 'complex', 'dict', 'enumerate', 'filter'] number helpers: (3, 2) 3 1024 5 3.14 text helpers: 65 ₹ 0xff 0b101 1,234,567
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 discover.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
Of its 150 public names, 70 are exceptions and warnings and 75 start with a small letter: the 70 documented
functions that do not start with an underscore, many of them types such as bool, dict and enumerate, plus
copyright, credits, exit, license and quit, which the site module adds for the interactive prompt. The
other five are the constants True, False, None, Ellipsis and NotImplemented, and help(name) shows the
documentation of any of them.
Checkpoint
Check: Choosing and finding built-ins
Check yourself
Each question checks one idea above, the least familiar first, and every choice explains itself.
Practice that adapts to you
Practise this lesson
13 questions about 12 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.
Edge cases that break built-ins, reproduced: empty input, NaN, rounding and float sums Pro: opens with a Pro, Premium or Ultimate pass
Most bugs with built-ins happen at the edges: an empty list, a missing reading, an amount that ends in a half. This part runs each edge case, explains the rule behind the result and shows the safe way to write it.
In this part:
- Empty input: what every built-in returns on nothing
- NaN poisons min, max and sorted, and the result depends on the order
- round() rounds half to even, and divmod() floors
- Float sums: sum() since Python 3.12 against math.fsum() and a plain loop
1 diagram · 4 runnable examples (Python) · about 8 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
Combining built-ins, with the work counted, and an exercise Pro: opens with a Pro, Premium or Ultimate pass
Built-ins pay off most when they are combined into one expression that states what you want. This part counts the
work that next() and key functions do, builds a leaderboard from five built-ins, settles the bool trap of
isinstance() and ends with an exercise.
In this part:
- next() with a default: the first failure without running every check
- Key functions run once per item, counted
- A leaderboard from sum, sorted, enumerate, zip and any
- isinstance() with unions, and the bool that counts as an int
- reversed() needs a sequence: what it accepts and what it refuses
- When a loop is clearer than a chain of built-ins, with the trade-offs
- Exercise: ten small jobs, ten built-ins
- Ten small jobs, ten built-in functions
5 runnable examples (Python) · 1 exercise with sample tests · about 9 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
Interview questions
-
Fresher · Warm-up
What do all([]) and any([]) return, and why?
all([]) returns True and any([]) returns False. all() returns False as soon as it finds a false item and True if it never finds one; an empty iterable has no false item, so the answer is True, which logicians call vacuous truth. any() returns True as soon as it finds a true item and False if it never finds one, so an empty iterable gives False. Both stop at the first item that settles the answer, which is why they are often given a generator expression. The empty case matters in practice: a check such as all(order.paid for order in orders) passes on a day with no orders, so when an empty input should not count as a pass, test for it separately.
-
Mid to senior
A daily report prints max() and min() of temperature readings from 2,000 sensors. On some days both show nan, on others normal numbers, although the same sensors are broken every day. Explain the behaviour and fix the report.
-
Fresher to senior
An invoice adds 40,000 line amounts stored as floats with sum(). Finance reports totals that differ from the ledger by a few paise. A colleague proposes math.fsum(). Do you agree? Explain what sum() does with floats on Python 3.14, and how you would store and add money.
-
Mid to senior
A survey tool totals the numeric answers of a form with sum(v for v in answers if isinstance(v, int)). Every ticked checkbox, stored as True, adds 1 to the total. Explain why, write a check that accepts integers and floats but not booleans, and say when type(v) is int is the better test.
Key takeaways
any()andall()stop at the first item that settles the answer, so feed them a generator expression.min()andmax()takekey=anddefault=and return the first of several equal items, andsum(iterable, start)adds numbers while"".join()joins strings.zip()andmap()stop silently at their shortest input, andstrict=Trueturns a mismatch intoValueError, formap()since Python 3.14.- A dozen built-ins cover most everyday loops, and
dir(builtins)andhelp()show the rest of the 71 documented functions.
Terms in this lesson
- built-in function
- A function Python provides in every module without an import, such as len(), sum() or zip(). Built-ins live in the builtins module, and dir(builtins) lists them with the built-in exceptions and constants.
- vacuous truth
- The rule that a statement about every item of an empty collection is true, because no item breaks it. It is why all([]) returns True while any([]) returns False.
References
- Built-in Functions (Python Software Foundation)
- Built-in Functions: any() and all() (Python Software Foundation)
- Built-in Functions: max() (Python Software Foundation)
- Built-in Functions: sum() (Python Software Foundation)
- Built-in Functions: map() (Python Software Foundation)
- Built-in Functions: round() (Python Software Foundation)
- builtins: Built-in objects (Python Software Foundation)
- Built-in Constants: constants added by the site module (Python Software Foundation)
- math.fsum() (Python Software Foundation)
- What's New In Python 3.12: sum() of floats (Python Software Foundation)
- PEP 618: Add Optional Length-Checking To zip (Python Software Foundation)
- Built-in Types: Mapping Types, dict (Python Software Foundation)
- Built-in Types: Boolean Type, bool (Python Software Foundation)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress