最近,我遇到了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
最佳答案
可以从下面使用自定义类的示例中看到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-3.x的 zip()
函数(或python 2.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
关于python - 了解比较中的可迭代类型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33080675/