`range(n, -1, -1)` 和 `reversed(range(0, n+1))` 之间有啥区别吗?
Posted
技术标签:
【中文标题】`range(n, -1, -1)` 和 `reversed(range(0, n+1))` 之间有啥区别吗?【英文标题】:Is there any difference between `range(n, -1, -1)` and `reversed(range(0, n+1))`?`range(n, -1, -1)` 和 `reversed(range(0, n+1))` 之间有什么区别吗? 【发布时间】:2015-04-12 18:15:22 【问题描述】:它们产生相同的结果。
>>> for i in range(10, -1, -1):
... print(i)
...
10
9
8
7
6
5
4
3
2
1
0
对比:
>>> for i in reversed(range(0, 10 + 1):
... print(i)
...
10
9
8
7
6
5
4
3
2
1
0
据我了解,Python3 的range
创建了一个生成器,而不是将整个范围存储在内存中。 reversed
同样一次生成一个值,我想。有什么理由使用其中一个吗?
【问题讨论】:
我猜range()
会比reverse()
更受欢迎,因为后者会导致更多的开销,但正确的分析只能通过记录两者的执行时间来完成
我一直认为反转不会生成生成器,但实际上会生成一个列表。根据 Python 3 文档,它是一个迭代器,但我怀疑它是一个生成器。 docs.python.org/3/library/…
大多数时候,选择实际上是在range(n-1, -1, -1)
和reversed(range(n))
之间。第二个选项是可读性的明显赢家,而且它更不容易出错。鉴于时间差异很小,并且循环体几乎总是占主导地位,我几乎总是选择reversed
。
@DovGrobgeld 这是错误的。 Python 有几种方法可以让reversed
避免将整个序列缓存在内存中。如果对象具有__reversed__
方法,则reversed
委托给该函数。或者,如果对象同时具有__len__
和__getitem__
方法,则从这些方法生成智能反向迭代器。只有当这两个选项都不可用时,reversed
才会将整个序列缓存在内存中。
@Dunes:实际上,它永远不会依赖于此。尝试reversed(reversed(range(10)))
,您会发现,外部的reversed
调用并没有尝试存储所有输出来反转它,而是抛出了一个错误。
【参考方案1】:
Python 中的reversed()
函数有一个特殊情况,当您将range()
传递给它时。 reversed(range(...))
和 range(...)
之间唯一真正的区别是您可以多次迭代 range()
,但 reversed()
返回一个迭代器,因此它只能使用一次。
>>> iter(range(0, 10))
<range_iterator object at 0x7f735f5badb0>
>>> reversed(range(0, 10))
<range_iterator object at 0x7f735f5baf30>
可以看到,在这两种情况下,迭代器类型都是range_iterator
。因此,循环本身的性能在两种情况下都是相同的。
由于reversed()
的唯一开销是一个额外的函数调用,我总是更喜欢reversed(range(10))
而不是range(9, -1, -1)
。
【讨论】:
【参考方案2】:这是在两个模块上使用timeit
的结果
bhargav@bhargav:~$ python -m timeit "for i in range(10, -1, -1):(i)"
1000000 loops, best of 3: 0.466 usec per loop
bhargav@bhargav:~$ python -m timeit "for i in reversed(range(0, 10 + 1)):(i)"
1000000 loops, best of 3: 0.531 usec per loop
如您所见,第二种方式较慢,因为它额外调用了函数reversed
。
【讨论】:
“这里还注意到生成器比迭代器快 3 倍。” - 这根本不是链接所说的。另外,range
不生成生成器,生成器是一种迭代器。
@user2357112 注意到了!我昨天才读到答案。也许我误解了!我很乐意删除误导性的话。再次感谢
我想我最好把我删除的两个链接留在这里。 1.Speed comparison between iterator and Generator 2.General Difference between Iterator and Generator【参考方案3】:
reversed
使它成为一个迭代器,因此取决于你如何使用它会有不同:
In [1]: r = reversed(range(0, 10 + 1))
In [2]: next(r)
Out[2]: 10
In [3]: r = range(10, -1, -1)
In [4]: next(r)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-4-0b5056469c9c> in <module>()
----> 1 next(r)
TypeError: 'range' object is not an iterator
【讨论】:
【参考方案4】:range(-n+1, -1, -1)
和reversed(range(n))
之间唯一真正的区别是range()
返回一个范围对象,在对其进行迭代之前可以进一步使用/操作。而reversed()
返回一个迭代器——你所能做的就是迭代它。
使用范围对象的示例,无法使用迭代器完成。
rng = range(20, 40, 2)
length = len(rng)
element = rng[0]
index_of_element = rng.index(element)
membership_test = 0 in rng
new_rng_from_slice = rng[2:5]
由于范围对象可以被切片,这也开辟了以另一种方式反转它们的可能性:
assert range(n)[::-1] == range(-n+1, -1, -1)
但是,除非需要范围对象的附加功能,否则reversed(range(n))
更可取,因为它更易于理解。
【讨论】:
以上是关于`range(n, -1, -1)` 和 `reversed(range(0, n+1))` 之间有啥区别吗?的主要内容,如果未能解决你的问题,请参考以下文章