理解比较中的可迭代类型

时间:2015-10-12 12:04:15

标签: python iterator

最近我遇到了cosmologicon的pywats,现在尝试了解迭代器的乐趣:

>>> a = 2, 1, 3
>>> sorted(a) == sorted(a)
True
>>> reversed(a) == reversed(a)
False

好的,sorted(a)会返回list,而sorted(a) == sorted(a)会变成两个列表比较。但是reversed(a)会返回reversed object。那么为什么这些反转的物体不同呢?而id的比较让我更加困惑:

>>> id(reversed(a)) == id(reversed(a))
True

4 个答案:

答案 0 :(得分:10)

id(reversed(a) == id(reversed(a)返回True,而reversed(a) == reversed(a)返回False的基本原因可以从下面的示例中看到,使用自定义类 -

>>> 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

正如您在customobject == customobject时所看到的那样,直到比较发生之后,动态创建的对象才被销毁,这是因为比较需要该对象。

但是在id(co) == id(co)的情况下,创建的自定义对象被传递给id()函数,然后只需要id函数的结果进行比较,因此创建的对象没有引用,因此对象是垃圾收集,然后当Python解释器为==操作的右侧重新创建一个新对象时,它重用了之前释放的空间。因此,两者的id都是一样的。

以上行为是CPython的一个实现细节(在其他Python实现中它可能/可能没有区别)。你永远不应该依赖ids的平等。例如,在下面的情况下,它给出了错误的结果 -

>>> a = [1,2,3]
>>> b = [4,5,6]
>>> id(reversed(a)) == id(reversed(b))
True

原因如上所述(在为reversed创建反向对象之前,为reversed(a)创建的reversed(b)对象的垃圾回收。)

如果列表很大,我认为最有效的内存和最可能最快的比较两个迭代器的相等性的方法是使用all()内置函数和Python的zip()函数3.x(或Python {x的itertools.izip())。

Python 3.x的示例 -

all(x==y for x,y in zip(aiterator,biterator))

Python 2.x的示例 -

from itertools import izip
all(x==y for x,y in izip(aiterator,biterator))

这是因为遇到第一个False值的all()短路,而Python 3.x中的`zip()返回一个迭代器,它从两个不同的迭代器中产生相应的元素。这不需要在内存中创建单独的列表。

演示 -

>>> 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

答案 1 :(得分:7)

signal clk : std_logic := '0'; 返回一个列表,而sorted返回一个reversed对象并且是另一个对象。如果您在比较之前将reversed的结果投射到列表中,它们将是相同的。

reversed

答案 2 :(得分:3)

reversed会返回一个不会实现特定__eq__运算符的迭代,因此会使用标识进行比较。

关于id(reversed(a)) == id(reversed(a))的混淆是因为在评估了第一个id(...)调用之后,可以处理iterable(没有引用它),第二个iterable可以在第二个{的同一个内存地址重新分配{ {1}}来电已完成。然而,这只是一个巧合。

尝试

id(...)

并将ra1 = reversed(a) ra2 = reversed(a) id(ra1)进行比较,您会看到它们是不同的数字(因为在这种情况下,无法解除可迭代对象,因为它们被id(ra2) / {引用{1}}变量)。

答案 3 :(得分:0)

您可以尝试list(reversed(a)) ==list(reversed(a))返回True

list(reversed(a))
[3, 2, 1]

一旦尝试

>>> v = id(reversed(a))
>>> n = id(reversed(a))
>>> v == n
False

再次

>>> v = id(reversed(a))
>>> n = id(reversed(a))
>>> n1 = id(reversed(a)) 
>>> v == n1
True