使用yield或__next__()实现可迭代对象:哪种更符合Python风格?
__next__(): Which is More Pythonic and Better? Great question—this is a common point of confusion when diving into Python's iteration system, and your intuition about yield being cleaner is totally on the mark. Let’s break down the differences, Pythonic style, and tradeoffs clearly:
1. Which is More Pythonic?
Without a doubt, yield—Python’s core philosophy emphasizes "Simple is better than complex" and "Readability counts", and yield nails both. When you use yield to create a generator, Python automatically handles the entire iterator protocol (the __iter__() and __next__() methods, plus raising StopIteration when the sequence ends) for you. You don’t have to manually track state (like self.i and self.n in your class example) or write repetitive boilerplate code for the iteration interface.
Compare your class-based iterator:
class iterable_class(): def __init__(self, n): self.i = 0 self.n = n def __iter__(self): return self def __next__(self): if self.i < self.n: i = self.i self.i += 1 return i else: raise StopIteration()
To an equivalent generator using yield:
def iterable_generator(n): i = 0 while i < n: yield i i += 1
The generator version is shorter, easier to parse at a glance, and leaves far less room for bugs (like forgetting to increment self.i or mishandling the StopIteration exception). This is exactly the kind of concise, expressive code Python was designed to encourage.
2. Performance: Is yield Faster?
In most practical use cases, the performance gap is negligible. That said, generators are implemented in optimized C under the hood, so they can be slightly faster than hand-written Python iterator classes in some scenarios. But don’t fixate on this—unless you’re working on a performance-critical loop with millions of iterations, the clarity of yield is far more valuable than marginal speed gains.
3. Are They Completely Interchangeable?
No, there are key tradeoffs to consider:
- Generators are one-shot: Once a generator is exhausted (raises
StopIteration), you can’t restart it—you have to create a new generator instance. With a custom iterator class, you can add methods to reset state (e.g., areset()method that setsself.i = 0), making it reusable without reinitializing the class. - Custom iterators offer more control: If you need extra functionality beyond just producing values (like methods to modify the sequence mid-iteration, or track additional state metrics), a class-based iterator is the better choice. Generators are focused solely on iterative value production.
- Generators are simpler for most cases: For 90% of iteration tasks, a generator will be sufficient and cleaner. Reserve class-based iterators for when you need that extra flexibility.
4. Do You Misunderstand yield?
It doesn’t seem like you do! Your sense that yield is more concise is exactly right. The key thing to remember is that generators are a higher-level abstraction of iterators—they let you write iterative code without dealing with the low-level details of the iterator protocol.
Final Recommendation
- Use
yieldgenerators for most iterative tasks: They’re more Pythonic, shorter, and easier to maintain. - Use a custom iterator class (with
__next__()) only when you need reusable state, additional methods, or fine-grained control over the iteration process.
内容的提问来源于stack exchange,提问作者Burton2000

