Python自定义迭代器类:两种__next__实现差异及临时变量必要性解析
self.x in a variable in a custom iterator? I'm trying to create a custom iterator using __iter__ and __next__ methods, and I came across this example code:
class OddNum: """Class to implement iterator protocol""" def __init__(self, num = 0): self.num = num def __iter__(self): self.x = 1 return self def __next__(self): if self.x <= self.num: odd_num = self.x self.x += 2 return odd_num else: raise StopIteration for num in OddNum(10): print(num)
When I run this, the output is 1 3 5 7 9. But if I remove the line odd_num = self.x and change return odd_num to return self.x (so the __next__ method updates self.x before returning it), the output becomes 3 5 7 9 11.
I'm confused about the difference between these two implementations—why do we need to store self.x in a variable before returning it?
Great question! Let's break down the core difference between these two implementations: it all comes down to the order of operations when handling the iterator's state.
First Implementation (with odd_num = self.x)
Let's walk through the first call to __next__ step by step:
- We check if
self.x(starting at1) is ≤self.num(10) — yes, it is. - We save the current value of
self.x(1) toodd_num. This preserves the value we want to return before modifying the iterator's state. - We update
self.xto1 + 2 = 3, preparing it for the next iteration. - We return
odd_num(1), which is the correct odd number we wanted to yield.
This follows standard iterator behavior: return the current valid element first, then advance the iterator to the next position. Each subsequent call repeats this logic, so we get all odd numbers from 1 up to 9 (once self.x becomes 11, the next call triggers StopIteration).
Second Implementation (without storing the variable)
When you remove the odd_num variable and adjust the return statement, your __next__ method effectively becomes:
def __next__(self): if self.x <= self.num: self.x += 2 return self.x else: raise StopIteration
Let's walk through this first call:
self.xis1, which is ≤10— proceed.- We immediately update
self.xto3before returning anything. - We return
3, skipping the initial value ofself.xentirely.
On each subsequent call, we keep updating self.x first, then returning the new value. This leads us to yield 3, 5, 7, 9, and finally 11 (since when self.x is 9, it's still ≤ 10 — we update to 11 and return it, even though 11 > 10). The iterator only stops on the next call, when self.x is 11 and fails the check.
Why the variable matters
Storing self.x in a variable lets us decouple returning the current element from advancing the iterator. Without it, we can't access the original value of self.x once we've updated it — we end up skipping the first element and including an element that's outside our intended range (11 in this case).
This is a common pattern in iterators: you need to capture the state before modifying it to ensure you return the correct value for the current iteration.
内容的提问来源于stack exchange,提问作者rodny9

