Python 在比较中理解iterable类型

Python 在比较中理解iterable类型,python,iterator,Python,Iterator,最近我遇到了cosmologicon,现在我试图了解迭代器的乐趣: >>> a = 2, 1, 3 >>> sorted(a) == sorted(a) True >>> reversed(a) == reversed(a) False 好的,sorted(a)返回一个列表,而sorted(a)=sorted(a)仅成为两个列表的比较。但是reversed(a)返回reversed对象。那么,为什么这些反向对象是不同的呢?id的比较让我更加

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

>>> a = 2, 1, 3
>>> sorted(a) == sorted(a)
True
>>> reversed(a) == reversed(a)
False
好的,
sorted(a)
返回一个
列表
,而
sorted(a)=sorted(a)
仅成为两个列表的比较。但是
reversed(a)
返回
reversed对象
。那么,为什么这些反向对象是不同的呢?id的比较让我更加困惑:

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

sorted
返回一个列表,而
reversed
返回一个
reversed
对象,是一个不同的对象。如果在比较之前将
反转的结果强制转换为列表,则它们将相等

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

In [9]: reversed(a)
Out[9]: <reversed at 0x2c989b0>
[8]中的
:反向(a)
出[8]:
在[9]中:反向(a)
出[9]:
您可以尝试
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

从下面使用自定义类的示例可以看出
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
原因同样如上所述(在为
reversed(b)
创建反向对象之前,对为
reversed(a)
创建的
reversed
对象进行垃圾收集)


如果列表很大,我认为比较两个迭代器的相等性的最有效、最快的方法是使用内置函数以及Python3.x(或Python2.x)的函数

Python 3.x的示例-

all(x==y for x,y in zip(aiterator,biterator))
Python2.x的示例-

from itertools import izip
all(x==y for x,y in izip(aiterator,biterator))
这是因为
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

reversed
返回一个iterable,该iterable未实现特定的
\uuuuu eq\uuuu
运算符,因此使用标识进行比较

关于
id(reversed(a))==id(reversed(a))
的混淆是因为在计算了第一个
id(…)
调用之后,可以释放iterable(没有引用它),并且当第二个
id(…)调用时,第二个iterable可以重新分配到相同的内存地址
呼叫已完成。但这只是巧合

试一试


然后将
id(ra1)
id(ra2)
进行比较,您将看到它们是不同的数字(因为在这种情况下,iterable对象无法解除分配,因为它们被
ra1
/
ra2
变量引用).

迭代器通常比较为False,因为在您这样做之前,您无法知道通过对迭代器进行迭代会得到什么。因此,比较返回False是因为反向
\uuuu eq\uuu
实现?
sorted
返回一个列表。在
iter(a)
反向(a)之间更公平的比较
。以这种方式比较id是一个典型的错误:好吧!这就解释了为什么
x=reversed(a)
y=reversed(a)
id(x)==id(y)
给出了
False
。谢谢。现在这对我来说绝对有意义了!所以
reversed(a)==reversed(a)
实际上是两个不同对象的比较!@valentjedi:注意
id()的行为
是特定于CPython的。如果你想让你的代码可以移植并与未来版本的CPython兼容,就不要依赖它。
v==n1
=>
True
如何实现?你的答案几乎无法解释任何事情。@AshwiniChaudhary try
id(反向(a))
在python Shell中连续运行5到10次。您将获得一些ID的重复,这是因为由于旧对象的垃圾收集,CPython可以重用该内存空间,如果已经存在对对象的引用,则新对象将使用一些不同的ID。
>>> 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
ra1 = reversed(a)
ra2 = reversed(a)