父类enumerate如何访问未作为子类实例变量存储的iterable参数?
enumerate Stores the Iterable Great question! Let's unpack what's happening here—it ties into how Python's built-in enumerate type works under the hood, and it's a neat example of how inheritance interacts with Python's low-level built-in implementations.
First, let's recap your code: you created a subclass of enumerate that overrides __next__ to return descending indices alongside ascending items. After simplifying, you noticed that even though you removed all code explicitly storing the iterable parameter, super().__next__() still somehow accesses it. Here's why:
enumerate stores the iterable in hidden internal attributes
enumerate is a built-in type implemented in C (not pure Python), which means its instance attributes aren't visible via standard Python tools like dir() or direct attribute access. When you create an instance of enumerate (or your revenumerate subclass), the constructor (a combination of __new__ and __init__ in the C implementation) saves a reference to the passed iterable in a hidden, internal structure.
Even though you didn't explicitly handle this in your subclass's __init__, the enumerate parent class's constructor runs automatically (thanks to inheritance) and takes care of storing the iterable for you. This storage happens entirely outside of Python's visible namespace, which is why you couldn't find it when inspecting builtins.py or using the PyCharm debugger.
How super().__next__() accesses the iterable
When you call super().__next__(), you're invoking the original enumerate iterator logic. This logic uses the internally stored iterable to generate the standard (index, item) pairs (starting from your specified start value). Your subclass's __next__ method then takes those pairs and transforms the index to be in descending order, while keeping the items in their original sequence.
A quick way to verify this is to modify your test case with a mutable iterable:
letters = ['a', 'b', 'c'] rev_iter = revenumerate(letters) letters[0] = 'z' # Modify the original list before iterating for i, letter in rev_iter: print('{}, {}'.format(i, letter))
You'll see the output uses the updated value z instead of a, which proves the enumerate instance is holding a live reference to the original iterable, not a copy.
A quick note on your code's len() dependency
One thing to keep in mind: your code calls len(iterable) in __init__, which means it only works with iterables that support the length protocol (like lists, tuples, dictionaries). It won't work with arbitrary iterables (like generators or file objects) because they don't have a defined length. But that's a separate detail from your original question about where the iterable is stored.
To wrap up: the iterable is stored in a hidden internal attribute of the enumerate instance, managed by Python's C implementation. Your subclass inherits this storage automatically, which is why super().__next__() can access it even without you handling it explicitly.
内容的提问来源于stack exchange,提问作者Campbell McDiarmid

