理解比较中的可迭代类型

val*_*tev 6 python iterator

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

>>> a = 2, 1, 3
>>> sorted(a) == sorted(a)
True
>>> reversed(a) == reversed(a)
False
Run Code Online (Sandbox Code Playgroud)

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

>>> id(reversed(a)) == id(reversed(a))
True
Run Code Online (Sandbox Code Playgroud)

Ana*_*mar 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
Run Code Online (Sandbox Code Playgroud)

正如您所看到的那样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
Run Code Online (Sandbox Code Playgroud)

其原因再次如上所述(在创建反向对象之前为reversed对象创建的对象的垃圾收集).reversed(a)reversed(b)


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

Python 3.x的示例 -

all(x==y for x,y in zip(aiterator,biterator))
Run Code Online (Sandbox Code Playgroud)

Python 2.x的示例 -

from itertools import izip
all(x==y for x,y in izip(aiterator,biterator))
Run Code Online (Sandbox Code Playgroud)

这是因为all()遇到第一个False值的短路,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
Run Code Online (Sandbox Code Playgroud)

  • 好的!这就解释了为什么`x = reverse(a)``y = reverse(a)``id(x)== id(y)`给出'False`.谢谢. (2认同)

Chr*_*tts 7

sorted返回一个列表,而reversed返回一个reversed对象并且是一个不同的对象.如果您reversed在比较之前将结果转换为列表,它们将是相等的.

In [8]: reversed(a)
Out[8]: <reversed at 0x2c98d30>

In [9]: reversed(a)
Out[9]: <reversed at 0x2c989b0>
Run Code Online (Sandbox Code Playgroud)