<p>另一个附加选项是查询iterable是否是它自己的迭代器:</p>
<pre><code>if iter(vals) is vals:
vals = list(vals)
</code></pre>
<p>因为在本例中,它只是一个迭代器。在</p>
<p>这适用于生成器、迭代器、文件和许多其他为“一次运行”而设计的对象,换句话说,所有iterable本身就是迭代器,因为<a href="http://docs.python.org/2/library/stdtypes.html#iterator.__iter__" rel="nofollow">iterator returns ^{<cd1>} from its ^{<cd2>}</a>。在</p>
<p>但这可能还不够,因为有些对象在迭代时会清空自己,而不是自己的迭代器。在</p>
<hr/>
<p>通常,一个自消费对象将是它自己的迭代器,但在某些情况下这可能是不允许的。在</p>
<p>假设有一个类包装了一个列表并在迭代时清空这个列表,比如</p>
^{pr2}$
<p>你叫它什么</p>
<pre><code>l = [1, 2, 3, 4]
lp = ListPart(l)
for i in lp: process(i)
# now l is empty.
</code></pre>
<p>如果我现在向该列表中添加额外的数据并再次迭代相同的对象,我将得到新的数据,即<a href="http://docs.python.org/2/library/stdtypes.html#iterator-types" rel="nofollow">breach of the protocol</a>:</p>
<blockquote>
<p>The intention of the protocol is that once an iterator’s <code>next()</code> method raises <code>StopIteration</code>, it will continue to do so on subsequent calls. Implementations that do not obey this property are deemed broken. (This constraint was added in Python 2.3; in Python 2.2, various iterators are broken according to this rule.)</p>
</blockquote>
<p>因此,在这种情况下,对象必须返回一个与自身不同的迭代器,尽管它是自消耗的。在这种情况下,可以用</p>
<pre><code>def __iter__(self):
while True:
try:
yield l.pop(0)
except IndexError: # pop from empty list
return
</code></pre>
<p>它在每次迭代中都返回一个新的生成器—在我们讨论的案例中,这个生成器可能会失败。在</p>