You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于OrderedDict的自定义迭代器类实现困惑:__next__与迭代器协议疑问

Hey there! Let's break this down step by step because iterators and iterables can feel tricky even after reading up on them. I get where you're stuck—let's start with a quick recap to align on basics, then dive into wrapping an OrderedDict with a custom iterator class to clear up your confusion.

Recap: Iterables vs. Iterators

First, let's make sure we're on the same page with the core concepts:

  • Iterable: Any object that implements the __iter__() method, which returns an iterator. Think of it as a "container" that can be looped over.
  • Iterator: An object that implements two methods:
    • __iter__(): Returns itself (so it can be used in loops like an iterable)
    • __next__(): Returns the next element in the sequence, and raises StopIteration when there are no more elements left.
Wrapping OrderedDict with a Custom Iterator

The good news is you don't have to reinvent the wheel when working with OrderedDict—it's already an iterable with built-in iterator support. We can reuse that existing logic while adding custom behavior. Let's walk through two common scenarios.

Scenario 1: Separate Iterable Class + Custom Iterator

This is the cleanest approach, as it separates the "container" (your wrapped OrderedDict) from the "iteration logic".

Step 1: Build the Custom Iterator

This iterator will take an OrderedDict and apply your custom processing to each element as it's iterated:

from collections import OrderedDict

class OrderedDictCustomIterator:
    def __init__(self, ordered_dict):
        # Store the original OrderedDict and its built-in items iterator
        self._odict = ordered_dict
        self._inner_iterator = iter(ordered_dict.items())
    
    def __iter__(self):
        # Iterators return themselves when __iter__ is called
        return self
    
    def __next__(self):
        # Get the next element from the OrderedDict's iterator
        key, value = next(self._inner_iterator)
        
        # Add your custom logic here!
        # Example: Convert string keys to uppercase
        if isinstance(key, str):
            return (key.upper(), value)
        # For non-string keys, return as-is
        return (key, value)

Step 2: Build the Wrapped Iterable Class

This class holds the OrderedDict and returns your custom iterator when __iter__() is called:

class WrappedOrderedDict:
    def __init__(self):
        self._internal_odict = OrderedDict()
    
    def add_entry(self, key, value):
        self._internal_odict[key] = value
    
    def __iter__(self):
        # Return our custom iterator tied to the internal OrderedDict
        return OrderedDictCustomIterator(self._internal_odict)

How to Use It

my_dict = WrappedOrderedDict()
my_dict.add_entry("name", "Alice")
my_dict.add_entry("age", 30)
my_dict.add_entry(1, "priority")

# Loop through our custom iterable
for k, v in my_dict:
    print(k, v)

Output:

NAME Alice
AGE 30
1 priority

Scenario 2: Single Class That's Both Iterable and Iterator

If you want a simpler (but less flexible) setup, you can make your wrapped class act as both the iterable and the iterator. Just remember to reset your iteration state in __iter__() so you can loop multiple times:

from collections import OrderedDict

class SelfContainedWrappedDict:
    def __init__(self):
        self._odict = OrderedDict()
        self._current_index = 0
        self._keys = []
    
    def add_entry(self, key, value):
        self._odict[key] = value
        # Update the key list whenever we add a new entry
        self._keys = list(self._odict.keys())
    
    def __iter__(self):
        # Reset index so we can start iterating from the beginning again
        self._current_index = 0
        return self
    
    def __next__(self):
        if self._current_index >= len(self._keys):
            # No more elements—raise the required StopIteration
            raise StopIteration
        
        # Get the current key/value and increment the index
        key = self._keys[self._current_index]
        value = self._odict[key]
        self._current_index += 1
        
        # Custom logic example: Return values doubled if they're numbers
        if isinstance(value, (int, float)):
            return (key, value * 2)
        return (key, value)

Usage Example

my_dict = SelfContainedWrappedDict()
my_dict.add_entry("count", 5)
my_dict.add_entry("message", "Hello")

# First loop
for k, v in my_dict:
    print(k, v)
# Output:
# count 10
# message Hello

# Second loop (works because __iter__ resets the index)
for k, v in my_dict:
    print(k, v)
Key Takeaways
  • You don't need to rewrite OrderedDict's iteration logic—reuse its built-in iterator (iter(odict), iter(odict.items()), etc.) to avoid bugs and save time.
  • The core of a custom iterator is the __next__() method: fetch the next element from the source, apply your custom logic, and let StopIteration be raised automatically when the source iterator runs out (or raise it manually if you're managing the index yourself).
  • For flexibility, separate your container (iterable) from your iteration logic (iterator)—this lets you add multiple iterator types to the same container if needed.

内容的提问来源于stack exchange,提问作者SirSteel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:25:19