<p><code>id(reversed(a) == id(reversed(a)</code>返回<code>True</code>,而<code>reversed(a) == reversed(a)</code>返回{<cd4>}的基本原因可以从下面使用自定义类的示例中看出-</p>
<pre><code>>>> class CA:
... def __del__(self):
... print('deleted', self)
... def __init__(self):
... print('inited', self)
...
>>> CA() == CA()
inited <__main__.CA object at 0x021B8050>
inited <__main__.CA object at 0x021B8110>
deleted <__main__.CA object at 0x021B8050>
deleted <__main__.CA object at 0x021B8110>
False
>>> id(CA()) == id(CA())
inited <__main__.CA object at 0x021B80F0>
deleted <__main__.CA object at 0x021B80F0>
inited <__main__.CA object at 0x021B80F0>
deleted <__main__.CA object at 0x021B80F0>
True
</code></pre>
<p>正如您在<code>customobject == customobject</code>时看到的,动态创建的对象直到比较发生后才被销毁,这是因为比较需要该对象。在</p>
<p>但是在<code>id(co) == id(co)</code>的情况下,创建的自定义对象被传递给<code>id()</code>函数,然后只需要<code>id</code>函数的结果进行比较,因此创建的对象没有剩余的引用,因此该对象是<em>垃圾回收的</em>,然后,当Python解释器为<code>==</code>操作的右侧重新创建一个新对象时,它会重用先前释放的空间。因此,两者的<code>id</code>是一样的。在</p>
<p>上面的行为是CPython的一个实现细节(在Python的其他实现中可能/可能没有不同)。而且你不应该依赖<code>ids</code>的相等性。例如,在下面的情况下,它给出了错误的结果-</p>
^{pr2}$
<p>原因还是如上所述(在为<code>reversed(b)</code>创建反向对象之前,对为<code>reversed(a)</code>创建的<code>reversed</code>对象进行垃圾回收)。在</p>
<hr/>
<p>如果列表很大,我认为比较两个迭代器的相等性的最有效的方法是使用<a href="https://docs.python.org/2/library/functions.html#all" rel="noreferrer">^{<cd15>}</a>内置函数和用于python3.x的<a href="https://docs.python.org/3/library/functions.html#zip" rel="noreferrer">^{<cd16>}</a>函数(对于python2.x使用<a href="https://docs.python.org/2/library/itertools.html#itertools.izip" rel="noreferrer">^{<cd17>}</a>)。在</p>
<p>python3.x的示例-</p>
<pre><code>all(x==y for x,y in zip(aiterator,biterator))
</code></pre>
<p>Python 2.x的示例-</p>
^{4}$
<p>这是因为遇到了第一个False值处的<code>all()</code>短路,python3.x中的`zip()返回一个迭代器,该迭代器从两个不同的迭代器中生成相应的元素。这不需要在内存中创建单独的列表。在</p>
<p>演示-</p>
<pre><code>>>> a = [1,2,3]
>>> b = [4,5,6]
>>> all(x==y for x,y in zip(reversed(a),reversed(b)))
False
>>> all(x==y for x,y in zip(reversed(a),reversed(a)))
True
</code></pre>