python 反向方法和反向内置函数哪个“更好”?

lmyy7pcs  于 2022-12-28  发布在  Python
关注(0)|答案(8)|浏览(186)

通常认为哪种方法更像Python/更好/更快,是相反的方法还是相反的内置函数?
两者都在行动:

_list = list(xrange(4))

print _list

rlist = list(reversed(_list))

print rlist

_list.reverse()

print _list
ijxebb2r

ijxebb2r1#

foo.reverse()实际上反转容器中的元素。reversed()实际上不反转任何东西,它只返回一个对象,该对象可用于以相反的顺序迭代容器的元素。如果这是您所需要的,则它通常比实际反转元素更快。

bqujaahr

bqujaahr2#

看起来有很大的不同。我真的认为是相反的。为什么重新排列列表中的值比从迭代器创建一个新的值要快?

from decorators import bench

_list = range(10 ** 6)

@ bench
def foo():
  list(reversed(_list))

@ bench
def bar():
  _list.reverse()

foo()
bar()

print foo.time
print bar.time

0.167278051376美元
0.0122621059418

huus2vyu

huus2vyu3#

这取决于你是否想在原处反转列表(即改变列表)。没有其他真实的的区别。
经常使用reversed会产生更好的代码。

bogh5gae

bogh5gae4#

_list.reverse()在不知道真实的性能统计信息的情况下修改列表本身,而reversed(_list)返回一个准备好以相反顺序遍历列表的迭代器,这本身就是一个很大的区别。
如果这不是问题,object.reverse()对我来说似乎更容易理解,但也许你有特定的速度要求,如果reverse()不属于80%的消耗资源的软件,我不会费心(作为一般的经验法则)。

6yoyoihd

6yoyoihd5#

  • _list.reverse()执行原地反转,但不返回值
  • reversed(_list)不改变_list,但返回反向可迭代对象
  • _list[::-1]不更改_list,但返回反转的切片

示例:

_list = [1,2,3]
ret1 = list(reversed(_list))
ret2 = _list[::-1] #reverse order slice
ret3 = _list.reverse() #no value set in ret3
print('ret1,ret2,ret3,_list:',ret1,ret2,ret3,_list)

_list = [1,2,3]
for x in reversed(_list):
    print(x)

输出:

ret1,ret2,ret3,_list: [3, 2, 1] [3, 2, 1] None [3, 2, 1]
3
2
1
oprakyz7

oprakyz76#

如果你最终要修改迭代器中的列表,使用reversed()总是更好的,使列表不可变,并且使用不可变数据总是更好,特别是在你做函数式编程的时候。

ngynwnxp

ngynwnxp7#

在@Niklas R上扩展答案:

import timeit

print('list.reverse() - real-list', timeit.timeit('_list.reverse()', '_list = list(range(1_000))'))
print('list.reverse() - iterator', timeit.timeit('_list = range(1_000); list(_list).reverse()'))  # can't really use .reverse() since you need to cast it first
print('reversed() - real-list', timeit.timeit('list(reversed(_list))', '_list = list(range(1_000))'))
print('reversed() - iterator', timeit.timeit('_list = range(1_000); list(reversed(_list))'))
print('list-comprehension - real-list', timeit.timeit('_list[::-1]', '_list = list(range(1_000))'))
print('list-comprehension - iterator', timeit.timeit('_list = range(1_000); _list[::-1]'))

结果:

list.reverse() - real-list 0.29828099999576807
list.reverse() - iterator 11.078685999964364  # can't really use .reverse() since you need to cast it first
reversed() - real-list 3.7131450000451878
reversed() - iterator 12.048991999938153
list-comprehension - real-list 2.2268580000381917
list-comprehension - iterator 0.4313809999730438

(* 越少越好/越快 *)

bxjv4tth

bxjv4tth8#

  • a将返回反向iterator的内置函数reversed(seq),反向iterator是表示将返回该流的连续项的数据流的对象。生成该反向迭代器在时间/空间复杂度上是O(1),并且使用它来迭代通过列表的元素将是O(N)O(1)的时间/空间复杂度,其中N是列表的长度。如果您只是想在不修改的情况下迭代反向列表,则需要使用这种方法。在这种情况下,这种方法可以提供最佳性能。
  • _list.reverse()就地反转列表。操作是O(N)O(1)的时间/空间复杂度,因为它必须遍历列表中一半的元素才能将其反转,并且它不会将结果存储在新列表中。如果您需要保留原始列表,并且您有几次遍历,则此方法很好/要对冲销列表的要素执行的操作,以及是否必须保存已处理的冲销列表。
  • 最后但并非最不重要的是,使用切片[::-1]创建列表的一个新对象/a逆序复制,操作为O(N)O(N)的空间/时间复杂性,因为您必须将列表的所有元素复制到新列表中,并且该新列表也将消耗与原始列表相同的空间量。如果您需要保留原始列表,并将其反向副本存储在不同的对象中以供进一步处理,那么这种方法非常有用。

总而言之,根据您的用例,您将不得不使用这三种目标略有不同、性能完全不同的方法之一。

相关问题