Table of Contents

    enumerate()

    CHAPTER 29.3 · ADVANCED PYTHON FEATURES

    enumerate() in Python

    Learn how to access both the position and value of each item while iterating over a Python iterable.

    While processing a list, tuple, string, or another iterable, programmers often need both the current item and its position. One approach is to create and update a counter manually.

    Python provides the built-in enumerate() function for this purpose. It produces pairs containing a counter and the corresponding item from the iterable.

    Learning objective: In this tutorial, you will learn the syntax of enumerate(), how to unpack its values, how to select a custom starting number, and how to use it with different iterable objects.

    Prerequisites

    What You Should Know

    • Python variables and basic data types
    • Lists, tuples, strings, and dictionaries
    • Using for loops
    • Tuple creation and tuple unpacking
    • Using if conditions
    • Basic understanding of iterable objects

    What is enumerate()?

    enumerate() is a built-in Python function that accepts an iterable and returns an enumerate object.

    During iteration, the enumerate object supplies pairs containing the current count and the corresponding value from the original iterable.

    Think of enumerate() as automatic serial numbering

    Imagine writing numbers beside items in a checklist. enumerate() automatically supplies those numbers while preserving access to each original item.

    Syntax

    ENUMERATE SYNTAX
    enumerate (iterable, start=0)
    enumerate(iterable, start=0)
    Parameter Requirement Purpose
    iterable Required Supplies the values to enumerate.
    start Optional Defines the first counter value. Its default value is zero.

    Basic enumerate() Example

    Use enumerate() to display the position and value of each programming language:

    languages = [
        "Python",
        "Java",
        "C#",
        "JavaScript"
    ]
    
    for index, language in enumerate(languages):
        print(index, language)

    Output:

    0 Python
    1 Java
    2 C#
    3 JavaScript

    On every iteration, Python unpacks the generated pair into index and language.

    What Does enumerate() Return?

    Calling enumerate() creates an enumerate object.

    languages = ["Python", "Java", "C#"]
    
    result = enumerate(languages)
    
    print(result)
    print(type(result))

    Possible output:

    <enumerate object at 0x...>
    <class 'enumerate'>
    Printing the enumerate object does not display all generated pairs. Iterate over it or convert it to a collection to inspect those pairs.

    Convert enumerate() to a List

    Convert an enumerate object to a list to view all generated index-value pairs:

    languages = [
        "Python",
        "Java",
        "C#"
    ]
    
    result = list(enumerate(languages))
    
    print(result)

    Output:

    [(0, 'Python'), (1, 'Java'), (2, 'C#')]

    Each element in the resulting list is a tuple containing the counter and the original value.

    Set a Custom Starting Number

    The optional start parameter changes the first counter value.

    languages = [
        "Python",
        "Java",
        "C#"
    ]
    
    for position, language in enumerate(
        languages,
        start=1
    ):
        print(position, language)

    Output:

    1 Python
    2 Java
    3 C#
    Use start=1 for serial numbers, rankings, user-facing menus, and other situations where counting from one is more natural.

    Manual Counter vs enumerate()

    Using a Manual Counter

    languages = [
        "Python",
        "Java",
        "C#"
    ]
    
    position = 1
    
    for language in languages:
        print(position, language)
        position += 1

    Using enumerate()

    languages = [
        "Python",
        "Java",
        "C#"
    ]
    
    for position, language in enumerate(
        languages,
        start=1
    ):
        print(position, language)

    Manual Counter

    • Requires a separate counter variable
    • Requires manual incrementing
    • The increment may be forgotten
    • Counter logic is mixed with business logic

    enumerate()

    • Provides the counter automatically
    • Supports a custom starting value
    • Keeps iteration logic concise
    • Clearly communicates the need for position and value

    Retrieve Pairs with next()

    An enumerate object is an iterator. The built-in next() function retrieves its next pair.

    languages = [
        "Python",
        "Java",
        "C#"
    ]
    
    language_iterator = enumerate(
        languages,
        start=1
    )
    
    print(next(language_iterator))
    print(next(language_iterator))
    print(next(language_iterator))

    Output:

    (1, 'Python')
    (2, 'Java')
    (3, 'C#')

    enumerate() Object Exhaustion

    An enumerate object is consumed as its pairs are requested. After all pairs are produced, the same object is exhausted.

    languages = ["Python", "Java"]
    
    numbered_languages = enumerate(
        languages,
        start=1
    )
    
    print(list(numbered_languages))
    print(list(numbered_languages))

    Output:

    [(1, 'Python'), (2, 'Java')]
    []
    Important Create a new enumerate object when the same iterable must be enumerated again.

    Use enumerate() with a List

    products = [
        "Laptop",
        "Keyboard",
        "Mouse",
        "Monitor"
    ]
    
    for serial_number, product in enumerate(
        products,
        start=1
    ):
        print(
            f"{serial_number}. {product}"
        )

    Output:

    1. Laptop
    2. Keyboard
    3. Mouse
    4. Monitor

    Use enumerate() with a Tuple

    departments = (
        "Finance",
        "Human Resources",
        "Information Technology"
    )
    
    for index, department in enumerate(departments):
        print(index, department)

    Output:

    0 Finance
    1 Human Resources
    2 Information Technology

    Use enumerate() with a String

    A string is iterable, so enumerate() can provide the position of each character.

    language = "Python"
    
    for index, character in enumerate(language):
        print(index, character)

    Output:

    0 P
    1 y
    2 t
    3 h
    4 o
    5 n

    Find All Matching Positions

    Locate every position where a character appears:

    text = "programming"
    
    positions = [
        index
        for index, character in enumerate(text)
        if character == "m"
    ]
    
    print(positions)

    Output:

    [6, 7]

    Unlike str.index(), this pattern can collect all matching positions rather than only one match.

    Use enumerate() with a Dictionary

    Iterating directly over a dictionary produces its keys:

    employee = {
        "name": "Amina",
        "department": "IT",
        "active": True
    }
    
    for index, key in enumerate(
        employee,
        start=1
    ):
        print(index, key)

    Output:

    1 name
    2 department
    3 active

    Enumerate Dictionary Items

    Use dictionary.items() when both the dictionary key and value are required.

    employee = {
        "name": "Amina",
        "department": "IT",
        "active": True
    }
    
    for position, item in enumerate(
        employee.items(),
        start=1
    ):
        key, value = item
    
        print(
            position,
            key,
            value
        )

    Output:

    1 name Amina
    2 department IT
    3 active True

    Nested unpacking can make the loop more concise:

    for position, (key, value) in enumerate(
        employee.items(),
        start=1
    ):
        print(position, key, value)

    Use enumerate() with a Set

    A set is iterable, so it can be used with enumerate(). However, sets do not represent a positional sequence.

    skills = {
        "Python",
        "SQL",
        "Git"
    }
    
    for count, skill in enumerate(
        skills,
        start=1
    ):
        print(count, skill)
    The generated count represents the iteration order, not a permanent position stored by the set. Use a sequence if stable positional meaning is required.

    Use enumerate() with a Generator

    squares = (
        number ** 2
        for number in range(1, 6)
    )
    
    for position, square in enumerate(
        squares,
        start=1
    ):
        print(position, square)

    Output:

    1 1
    2 4
    3 9
    4 16
    5 25

    Filter by Position

    Use the generated index inside a condition. The following example processes values at even-numbered indexes:

    values = [
        "A",
        "B",
        "C",
        "D",
        "E",
        "F"
    ]
    
    for index, value in enumerate(values):
        if index % 2 == 0:
            print(index, value)

    Output:

    0 A
    2 C
    4 E

    Filter by Item Value

    scores = [
        72,
        35,
        91,
        28,
        64
    ]
    
    for position, score in enumerate(
        scores,
        start=1
    ):
        if score >= 40:
            print(
                f"Student {position}: Passed"
            )

    Output:

    Student 1: Passed
    Student 3: Passed
    Student 5: Passed

    Update List Values by Index

    The index provided by enumerate() can be used to update values in a mutable sequence.

    prices = [
        100,
        250,
        500
    ]
    
    for index, price in enumerate(prices):
        prices[index] = round(
            price * 1.10,
            2
        )
    
    print(prices)

    Output:

    [110.0, 275.0, 550.0]
    Updating existing positions may be appropriate, but avoid inserting or removing list elements while iterating over the same list. Structural changes can make iteration behavior difficult to understand.

    Find the Position of a Matching Item

    products = [
        "Laptop",
        "Keyboard",
        "Mouse",
        "Monitor"
    ]
    
    target_product = "Mouse"
    found_position = None
    
    for position, product in enumerate(
        products,
        start=1
    ):
        if product == target_product:
            found_position = position
            break
    
    print(found_position)

    Output:

    3

    Create a Numbered Menu

    menu_options = [
        "Create Record",
        "Update Record",
        "View Record",
        "Exit"
    ]
    
    print("Application Menu")
    
    for option_number, option in enumerate(
        menu_options,
        start=1
    ):
        print(
            f"{option_number}. {option}"
        )

    Output:

    Application Menu
    1. Create Record
    2. Update Record
    3. View Record
    4. Exit

    Enumerate a Nested List

    Use nested enumerate() calls to obtain row and column positions.

    matrix = [
        [10, 20, 30],
        [40, 50, 60]
    ]
    
    for row_index, row in enumerate(matrix):
        for column_index, value in enumerate(row):
            print(
                row_index,
                column_index,
                value
            )

    Output:

    0 0 10
    0 1 20
    0 2 30
    1 0 40
    1 1 50
    1 2 60

    Number Lines from a File

    The start parameter is useful when displaying human-readable line numbers.

    with open(
        "notes.txt",
        mode="r",
        encoding="utf-8"
    ) as notes_file:
    
        for line_number, line in enumerate(
            notes_file,
            start=1
        ):
            print(
                line_number,
                line.rstrip()
            )

    Each file line is processed one at a time and accompanied by its corresponding line number.

    Use enumerate() in List Comprehension

    Create formatted labels containing serial numbers and values:

    departments = [
        "Finance",
        "Sales",
        "Information Technology"
    ]
    
    numbered_departments = [
        f"{number}. {department}"
        for number, department in enumerate(
            departments,
            start=1
        )
    ]
    
    print(numbered_departments)

    Output:

    ['1. Finance', '2. Sales', '3. Information Technology']

    Combine enumerate() with zip()

    zip() combines corresponding values from multiple iterables. enumerate() can add a serial number to every combined record.

    names = [
        "Amina",
        "Rahul",
        "David"
    ]
    
    departments = [
        "IT",
        "Finance",
        "Sales"
    ]
    
    for employee_number, employee_data in enumerate(
        zip(names, departments),
        start=1
    ):
        name, department = employee_data
    
        print(
            employee_number,
            name,
            department
        )

    Output:

    1 Amina IT
    2 Rahul Finance
    3 David Sales

    Nested unpacking can also be used:

    for employee_number, (name, department) in enumerate(
        zip(names, departments),
        start=1
    ):
        print(
            employee_number,
            name,
            department
        )

    Practical Example: Number Customer Orders

    orders = [
        {
            "order_number": "ORD-101",
            "amount": 750
        },
        {
            "order_number": "ORD-102",
            "amount": 1500
        },
        {
            "order_number": "ORD-103",
            "amount": 2200
        }
    ]
    
    for serial_number, order in enumerate(
        orders,
        start=1
    ):
        print(
            f"{serial_number}. "
            f"{order['order_number']} - "
            f"{order['amount']}"
        )

    Output:

    1. ORD-101 - 750
    2. ORD-102 - 1500
    3. ORD-103 - 2200

    The start Value Is a Counter

    The starting value does not change the underlying iterable or its actual sequence indexes.

    colors = [
        "Red",
        "Green",
        "Blue"
    ]
    
    for count, color in enumerate(
        colors,
        start=100
    ):
        print(count, color)

    Output:

    100 Red
    101 Green
    102 Blue
    Although the first generated count is 100, the first list item still exists at list index zero. The count and the sequence index should not be treated as identical when a custom start is used.

    Common Mistakes

    1

    Forgetting to Unpack the Pair

    Each iteration produces a pair containing the count and item.

    Recommended Pattern for index, value in enumerate(values):
    2

    Expecting Counting to Start at One

    The default counter begins at zero.

    Solution Use start=1 when user-facing numbering should begin at one.
    3

    Confusing Counter with Actual List Index

    A custom starting value changes the generated count but not the underlying list indexes.

    Solution Use the default start value when the counter will be used for direct list indexing.
    4

    Trying to Reuse a Consumed enumerate Object

    An enumerate object is an iterator and becomes exhausted.

    Solution Call enumerate() again when another iteration is required.
    5

    Using enumerate() When the Position Is Unnecessary

    Adding an unused counter makes the loop more complicated.

    Solution Use a normal for item in iterable loop when only the item is required.

    When to Use enumerate()

    Good Use Cases

    • Displaying serial numbers beside values
    • Creating numbered menus
    • Processing file lines with line numbers
    • Updating list values using their indexes
    • Finding all positions of matching values
    • Processing rows and columns in nested lists
    • Adding record numbers to combined zip results
    • Replacing manually maintained counters

    When enumerate() Is Unnecessary

    Use a Simpler Loop When

    • Only the item value is required.
    • The position is never referenced inside the loop.
    • You are iterating over dictionary items and do not need an additional serial number.
    • A direct membership test can solve the problem without iteration.

    Best Practices

    Recommended Practices

    • Use descriptive variable names such as index, position, or line_number.
    • Use start=1 for human-readable numbering.
    • Keep the default start when the value represents a zero-based sequence index.
    • Use nested unpacking carefully when enumerating dictionary items or zipped values.
    • Avoid structural modification of a list during iteration.
    • Do not use enumerate() when the counter is unnecessary.

    Hands-On Practice

    Practice Exercises

    • Print a numbered list of five programming languages.
    • Display every character and its position in a string.
    • Find all indexes where a particular number appears in a list.
    • Create a menu whose numbering begins at one.
    • Increase every price in a list by five percent using its index.
    • Enumerate dictionary items and print serial number, key, and value.
    • Use nested enumerate() to display matrix coordinates.
    • Combine enumerate() and zip() to display numbered employee records.

    Knowledge Check

    1

    What does enumerate() return?

    It returns an enumerate object that produces pairs containing a count and an item from the iterable.

    2

    What is the default starting value?

    The default starting value is zero.

    3

    How do you start counting at one?

    for position, item in enumerate(
        values,
        start=1
    ):
        print(position, item)
    4

    Can enumerate() work with a string?

    Yes. A string is iterable, so its characters can be enumerated.

    5

    Does start=1 change the actual list indexes?

    No. It changes only the generated counter values.

    enumerate() Quick Reference

    # Basic enumeration
    for index, item in enumerate(iterable):
        print(index, item)
    
    # Start counting at one
    for position, item in enumerate(
        iterable,
        start=1
    ):
        print(position, item)
    
    # Convert to a list of tuples
    numbered_items = list(
        enumerate(iterable)
    )
    
    # Retrieve one pair
    iterator = enumerate(iterable)
    index, item = next(iterator)
    
    # Enumerate dictionary items
    for position, (key, value) in enumerate(
        dictionary.items(),
        start=1
    ):
        print(position, key, value)
    
    # Enumerate zipped values
    for position, (first, second) in enumerate(
        zip(first_values, second_values),
        start=1
    ):
        print(position, first, second)
    
    # Create numbered labels
    labels = [
        f"{position}. {item}"
        for position, item in enumerate(
            iterable,
            start=1
        )
    ]
    
    # Find matching indexes
    indexes = [
        index
        for index, item in enumerate(iterable)
        if item == target
    ]

    Summary

    What You Learned

    • enumerate() provides a counter and item during iteration.
    • The default counter begins at zero.
    • The start argument sets a custom initial counter value.
    • An enumerate object produces count-item tuples.
    • Tuple unpacking provides direct access to both generated values.
    • enumerate() works with lists, tuples, strings, dictionaries, generators, and other iterables.
    • An enumerate object becomes exhausted after its values are consumed.
    • A custom counter does not change the original sequence indexes.

    Key Takeaway

    Use enumerate() whenever a loop requires both an item's position and its value. It removes manual counter management, supports custom starting values, and makes indexed iteration clearer and less error-prone.