Python
Generators
Programming
Code Tutorial
Python Tips

How to pick just one item from a generator?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

To pick one item from a Python generator, use next(generator). This advances the generator to its first yield and returns the value. If the generator is exhausted, next() raises StopIteration — use next(generator, default) to return a default value instead. For picking a specific item, combine next() with itertools.islice() or a generator expression with a filter condition. The key advantage of using next() over converting to a list is that it does not consume the entire generator.

Basic: next()

python
1def count_up():
2    n = 1
3    while True:
4        yield n
5        n += 1
6
7gen = count_up()
8
9# Pick the first item
10first = next(gen)
11print(first)  # 1
12
13# Pick the second item (generator remembers its position)
14second = next(gen)
15print(second)  # 2
16
17# Pick the third
18third = next(gen)
19print(third)  # 3

Each call to next() advances the generator by one step. The generator retains its internal state between calls.

Handling Exhausted Generators

python
1def limited():
2    yield "a"
3    yield "b"
4
5gen = limited()
6print(next(gen))  # "a"
7print(next(gen))  # "b"
8
9# Generator is exhausted
10# next(gen)  # Raises StopIteration
11
12# Use a default value to avoid the exception
13print(next(gen, "nothing"))  # "nothing"
14print(next(gen, None))       # None

The two-argument form next(gen, default) returns the default when the generator has no more items, avoiding the need for try/except.

Pick the First Matching Item

python
1# Generator expression with a condition
2numbers = iter(range(100))
3first_even_over_50 = next(x for x in numbers if x > 50 and x % 2 == 0)
4print(first_even_over_50)  # 52
5
6# Finding a matching item in a large dataset
7def read_large_file(path):
8    with open(path) as f:
9        for line in f:
10            yield line.strip()
11
12# Stops reading as soon as the first match is found
13first_error = next(
14    (line for line in read_large_file("app.log") if "ERROR" in line),
15    "No errors found"
16)
17print(first_error)

The generator expression (x for x in gen if condition) is lazy — it only processes elements until the condition is met, then stops.

Pick the Nth Item with islice

python
1from itertools import islice
2
3def fibonacci():
4    a, b = 0, 1
5    while True:
6        yield a
7        a, b = b, a + b
8
9# Get the 10th Fibonacci number (0-indexed)
10gen = fibonacci()
11tenth = next(islice(gen, 10, 11))
12print(tenth)  # 55
13
14# Get the first 5 items as a list
15gen = fibonacci()
16first_five = list(islice(gen, 5))
17print(first_five)  # [0, 1, 1, 2, 3]
18
19# Skip the first 100 items, take the next one
20gen = fibonacci()
21item_101 = next(islice(gen, 100, 101))
22print(item_101)  # 354224848179261915075

islice(gen, start, stop) efficiently skips items without materializing them. It is the standard way to access a specific position in a generator.

Pick a Random Item

python
1import random
2from itertools import islice
3
4def data_stream():
5    for i in range(1000):
6        yield f"item-{i}"
7
8# Method 1: Reservoir sampling (O(n) memory: O(1))
9def random_from_generator(gen):
10    chosen = next(gen)
11    for i, item in enumerate(gen, start=2):
12        if random.randint(1, i) == 1:
13            chosen = item
14    return chosen
15
16result = random_from_generator(data_stream())
17print(result)  # Random item from the stream
18
19# Method 2: If you know the length, pick an index
20gen = data_stream()
21n = 1000
22idx = random.randrange(n)
23random_item = next(islice(gen, idx, idx + 1))
24print(random_item)

Reservoir sampling picks a uniformly random item from a generator of unknown length in a single pass with O(1) memory.

Pick Last Item

python
1from collections import deque
2
3def limited_gen():
4    yield 1
5    yield 2
6    yield 3
7
8# Method 1: deque with maxlen=1
9last = deque(limited_gen(), maxlen=1)[0]
10print(last)  # 3
11
12# Method 2: Loop to the end
13gen = limited_gen()
14for last_item in gen:
15    pass
16print(last_item)  # 3
17
18# Method 3: Consume and return last (functools.reduce)
19from functools import reduce
20last = reduce(lambda _, x: x, limited_gen())
21print(last)  # 3

All methods consume the entire generator. deque(gen, maxlen=1) is the most memory-efficient — it discards all but the last element.

Pick Multiple Items

python
1from itertools import islice
2
3def infinite_stream():
4    i = 0
5    while True:
6        yield f"event-{i}"
7        i += 1
8
9gen = infinite_stream()
10
11# Pick first 3
12batch1 = list(islice(gen, 3))
13print(batch1)  # ['event-0', 'event-1', 'event-2']
14
15# Pick next 3 (generator remembers position)
16batch2 = list(islice(gen, 3))
17print(batch2)  # ['event-3', 'event-4', 'event-5']
18
19# Batch processing pattern
20def batched(gen, size):
21    while True:
22        batch = list(islice(gen, size))
23        if not batch:
24            break
25        yield batch
26
27for batch in batched(infinite_stream(), 5):
28    print(batch)
29    if batch[-1] == "event-14":
30        break

Common Pitfalls

  • Converting to a list to pick one item: list(generator)[0] works but consumes the entire generator into memory. For infinite generators, this hangs forever. Use next(gen) instead — it only fetches one item.
  • Forgetting that generators are single-use: After calling next() or iterating partially, you cannot restart a generator. To iterate again, create a new generator instance. Calling next() on an exhausted generator raises StopIteration.
  • Not providing a default to next(): next(gen) raises StopIteration if the generator is empty. This is often unexpected. Use next(gen, None) or next(gen, default_value) to handle empty generators gracefully.
  • Using next() inside a for loop on the same generator: for item in gen and next(gen) both advance the same generator. Mixing them causes skipped items. Use one approach consistently or be explicit about consuming items.
  • Assuming islice returns a generator: islice returns an islice iterator, not a list. To get a single value, wrap it in next(): next(islice(gen, n, n+1)). Calling list(islice(gen, n)) returns a list of the first n items.

Summary

  • Use next(gen) to pick the first (or next) item from a generator
  • Use next(gen, default) to avoid StopIteration on empty generators
  • Use next(x for x in gen if condition) to find the first matching item
  • Use itertools.islice(gen, n, n+1) to pick the nth item without consuming the whole generator
  • Use reservoir sampling for picking a random item from a generator of unknown length
  • Generators are single-use and stateful — next() advances them permanently

Course illustration
Course illustration

All Rights Reserved.