在比较中理解iterable类型

2024-10-03 21:28:48 发布

您现在位置:Python中文网/ 问答频道 /正文

最近我遇到了宇宙逻辑的pywats,现在试着理解迭代器的乐趣部分:

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

好的,sorted(a)返回一个listsorted(a) == sorted(a)只是两个列表的比较。但是reversed(a)返回reversed object。那么为什么这些颠倒的物体是不同的呢?而id的比较让我更加困惑:

^{pr2}$

Tags: idfalsetrue列表object宇宙逻辑list
3条回答

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

>>> 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的相等性。例如,在下面的情况下,它给出了错误的结果-

^{pr2}$

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


如果列表很大,我认为比较两个迭代器的相等性的最有效的方法是使用^{}内置函数和用于python3.x的^{}函数(对于python2.x使用^{})。在

python3.x的示例-

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

Python 2.x的示例-

^{4}$

这是因为遇到了第一个False值处的all()短路,python3.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

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

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

In [9]: reversed(a)
Out[9]: <reversed at 0x2c989b0>

reversed返回不实现特定__eq__运算符的iterable,因此使用identity进行比较。在

关于id(reversed(a)) == id(reversed(a))的混淆是因为在对第一个id(...)调用求值后,可以释放iterable(没有引用它),并且第二个iterable可能在第二个id(...)调用完成时重新分配到同一个内存地址。不过,这只是一个巧合。在

试试看

ra1 = reversed(a)
ra2 = reversed(a)

id(ra1)与{}进行比较,就会发现它们是不同的数字(因为在本例中,iterable对象不能被释放,因为它们被ra1/ra2变量引用)。在

相关问题 更多 >