Python如何实现str [:: - 1]?

时间:2016-07-03 03:23:04

标签: python slice reverse

考虑一条python线:

str[::-1]

我发现它非常快,并且比某些 O(n)解决方案更快,也节省了内存。在这种情况下,Python使用什么算法?

2 个答案:

答案 0 :(得分:3)

嗯,你有没有尝试过任何快速和肮脏的测试?这是第一遍:

In [1]: import time

In [2]: def reverse_list_time(my_list):
   ...:     start  = time.time()
   ...:     reversed = my_list[::-1]
   ...:     stop = time.time()
   ...:     return stop - start
   ...: 

In [3]: reverse_list_time(list(range(1000)))
Out[3]: 1.33514404296875e-05

In [4]: testing_lists = (list(range(n)) for n in range(1000,100000,500))

In [5]: testing_lists
Out[5]: <generator object <genexpr> at 0x7f7786bd97d8>

In [6]: results = list(map(reverse_list_time,testing_lists))

这是我的结果

enter image description here

对我来说,这看起来大致是O(n)。

如果这并不能说服你,那么这里就是the implementation。对我来说,它看起来像是一个非常直接的O(n)解决方案。这是它的核心:

    else {
        result = PyList_New(slicelength);
        if (!result) return NULL;

        src = self->ob_item;
        dest = ((PyListObject *)result)->ob_item;
        for (cur = start, i = 0; i < slicelength;
             cur += step, i++) {
            it = src[cur];
            Py_INCREF(it);
            dest[i] = it;
        }

        return result;

答案 1 :(得分:2)

您可以使用Python的dis.dis模块来反汇编str[::-1]

>>> import dis
>>> def reverse_(str_):
...     return str_[::-1]
...
>>> dis.dis(reverse_)
  6           0 LOAD_FAST                0 (str_)
              3 LOAD_CONST               0 (None)
              6 LOAD_CONST               0 (None)
              9 LOAD_CONST               1 (-1)
             12 BUILD_SLICE              3
             15 BINARY_SUBSCR       
             16 RETURN_VALUE    

您可以在documentation中查看每条指令的含义。对于LOAD_FAST,文档说:

  

将对本地co_varnames[var_num]的引用推送到堆栈。

co_varnames是一个始终与代码对象一起出现的结构。在这种情况下,它是str_

>>> reverse_.__code__.co_varnames
('str_',)

下一条指令LOAD_CONST的描述如下:

  

co_consts[consti]推入堆栈。

推入堆栈的值为Nonedis很有帮助,并为您查找)。接下来的两条指令是LOAD_CONST指令,用于将值None-1推送到堆栈。

下一条指令BUILD_SLICE被描述为:

  

将切片对象推送到堆栈上。 argc必须是2或3.如果是2,则推送slice(TOS1, TOS);如果是3,则推送slice(TOS2, TOS1, TOS)。有关详细信息,请参阅slice()内置函数。

TOS2, TOS1, TOS表示堆栈None, None, -1上的值,这些值从堆栈推送到slice()对象(对象变为slice(None, None, -1))。

BINARY_SUBSCR被描述为:

  

实施TOS = TOS1[TOS]

这意味着Python计算str_[sli],其中sli是在前一条指令中推送到堆栈的slice()对象。

相当于

>>> str_[slice(None, None, -1)]

最后,RETURN_VALUE

  

使用TOS返回函数的调用者。

最后一条指令返回上一步的结果,即反转str_

摘要

  

我认为它非常快,并且比某些O(n)解决方案更快,也节省了内存。

实际上,通过切片反转列表涉及比Python中的其他反转方法更多的内存开销。长话短说(并且没有长长的兔子洞),因为切片操作返回整个列表,所以会发生更大的内存开销。

一种替代方法可能是:使用reversed()生成迭代器,这通常对内存和时间更有效(尽管从此迭代器生成列表非常耗时)。

  

在这种情况下,Python使用什么算法?

简而言之:Python加载变量str,构建slice(None, None, -1)对象,实现str[slice(None, None, -1)]source code),并返回反转的{{1} }}