为什么在Python中反转和排序不同的类型?

时间:2017-08-14 11:19:08

标签: python types python-internals

reversed的类型是"输入":

>>> type(reversed)
<class 'type'>

sorted&#39;类型是&#34;内置函数或方法&#34;:

>>> type(sorted)
<class 'builtin_function_or_method'>

然而,它们在性质上看起来是一样的。排除功能上的明显差异(逆转与排序序列),实现这种差异的原因是什么?

2 个答案:

答案 0 :(得分:51)

不同之处在于reversed是一个迭代器(它也是懒惰的评估),而sorted是一个可以正常工作的函数。#/ p>

所有内置迭代器(至少在python-3.x中),如mapzipfilterreversed,...实现为<强>类即可。虽然热切操作的内置插件是功能,例如minmaxanyallsorted

>>> a = [1,2,3,4]
>>> r = reversed(a)
<list_reverseiterator at 0x2187afa0240>

你实际上需要&#34;消费&#34;获取值的迭代器(例如list):

>>> list(r)
[4, 3, 2, 1]

另一方面,这&#34;消费&#34; 功能需要部分,例如sorted

>>> s = sorted(a)
[1, 2, 3, 4]

在评论中,有人问为什么将这些实现为类而不是函数。这并不容易回答,但我会尽我所能:

使用延迟评估操作有一个巨大的好处:链接时它们的内存效率非常高。他们不需要创建中间列表,除非他们明确地要求&#34;。这就是为什么mapzipfilter从急切操作函数(python-2.x)更改为延迟操作类(python-3.x)的原因。< / p>

通常,Python有两种方法来创建迭代器:

  • return self方法
  • __iter__的课程
  • 生成器函数 - 包含yield
  • 的函数

然而(至少CPython)在C中实现了所有内置函数(和几个标准库模块)。在C中创建迭代器类非常容易,但我还没有找到任何合理的方法基于Python-C-API创建生成器函数。因此,将这些迭代器实现为类(在CPython中)的原因可能只是方便或缺少(快速或可实现的)替代方案。

使用类而不是生成器还有另外一个原因:您可以为类实现特殊方法,但不能在生成器函数上实现它们。这听起来可能并不令人印象深刻,但它有一定的优例如,大多数迭代器可以使用pickled__reduce__方法__setstate__(至少在Python-3.x上)。这意味着您可以将它们存储在磁盘上,并允许复制它们。从Python-3.4开始,一些迭代器也实现了__length_hint__,这使得使用list(和类似)的迭代器的速度要快得多。

请注意,reversed可以轻松实现为工厂功能(如iter),但不像iter,它可以返回两个唯一的类,{{ 1}}只能返回一个唯一的类。

为了说明可能的(和唯一的)类,您必须考虑一个没有__iter__且没有__reversed__方法但可迭代和反向迭代的类(通过实现__getitem____len__):

reversed

虽然在class A(object): def __init__(self, vals): self.vals = vals def __len__(self): return len(self.vals) def __getitem__(self, idx): return self.vals[idx] 的情况下添加抽象层(工厂函数)是有意义的 - 因为返回的类取决于输入参数的数量:

iter

这种推理并不适用于>>> iter(A([1,2,3])) <iterator at 0x2187afaed68> >>> iter(min, 0) # actually this is a useless example, just here to see what it returns <callable_iterator at 0x1333879bdd8>

reversed

答案 1 :(得分:4)

  

reversedsorted之间有什么区别?

有趣的是,reversed不是函数,而sorted是。

打开REPL会话并输入help(reversed)

class reversed(object)
 |  reversed(sequence) -> reverse iterator over values of the sequence
 |  
 |  Return a reverse iterator

它确实是一个用于返回反向迭代器的类。

  

好的,reversed不是函数。但为什么不呢?

这有点难以回答。一种解释是迭代器具有惰性评估。这需要某种容器来存储有关任何给定时间迭代器当前状态的信息。这最好通过一个对象完成,因此,class