简体   繁体   English

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

[英]How does Python implement str[::-1]?

Consider a python line: 考虑一条python行:

str[::-1]

I see it's very fast, and way more faster than some O(n) solution and also memory saving. 我看到它非常快,并且比某些O(n)解决方案要快得多,并且还节省了内存。 What algorithm does Python use in this case? 在这种情况下,Python使用什么算法?

Hmm, have you tried any quick-and-dirty tests? 嗯,您是否尝试过任何快速和肮脏的测试? Here is a first-pass: 这是第一次通过:

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))

And here are my results 这是我的结果

在此处输入图片说明

That looks roughly O(n) to me. 在我看来,这大概是O(n)。

If that doesn't convince you, here is the implementation . 如果那不能使您信服,则这里是实现 It looks like a pretty straight forward O(n) solution to me. 对我来说,这似乎是一个非常简单的O(n)解决方案。 This is the meat of it: 这是它的实质:

  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; 

You can use Python's dis.dis module to disassemble str[::-1] : 您可以使用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    

You can see what each instruction means in the documentation . 您可以在文档中查看每个说明的含义。 For LOAD_FAST the docs say: 对于LOAD_FAST ,文档说:

Pushes a reference to the local co_varnames[var_num] onto the stack. 将对本地co_varnames[var_num]的引用co_varnames[var_num]入堆栈。

co_varnames is a structure that is always present with a code object. co_varnames是代码对象始终存在的结构。 In this case, it is str_ : 在这种情况下,它是str_

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

The next instruction, LOAD_CONST , is described like this: 下一条指令LOAD_CONST的描述如下:

Pushes co_consts[consti] onto the stack. co_consts[consti]入堆栈。

The value that was pushed onto the stack is None ( dis is helpful and looked it up for you). 被压入堆栈的值是Nonedis会有所帮助,并会为您查找)。 The next two instructions are LOAD_CONST instructions that push the values None and -1 onto the stack. 接下来的两条指令是LOAD_CONST指令,它们将值None-1推入堆栈。

The next instruction, BUILD_SLICE , is described as: 下一条指令BUILD_SLICE描述为:

Pushes a slice object on the stack. 将切片对象压入堆栈。 argc must be 2 or 3. If it is 2, slice(TOS1, TOS) is pushed; argc必须为2或3。如果为2, slice(TOS1, TOS)压入; if it is 3, slice(TOS2, TOS1, TOS) is pushed. 如果为3,则slice(TOS2, TOS1, TOS)被压入。 See the slice() built-in function for more information. 有关更多信息,请参见slice()内置函数。

TOS2, TOS1, TOS represent the values on the stack None, None, -1 , which are pushed to the slice() object from the stack (the object becomes slice(None, None, -1) ). TOS2, TOS1, TOS表示堆栈None, None, -1上的值,这些值从堆栈推送到slice()对象(对象变为slice(None, None, -1) )。

BINARY_SUBSCR is described as: BINARY_SUBSCR被描述为:

Implements TOS = TOS1[TOS] . 实现TOS = TOS1[TOS]

This means that Python computes str_[sli] where sli is the slice() object pushed to the stack in the previous instruction. 这意味着Python将计算str_[sli] ,其中sli是上sli指令中压入堆栈的slice()对象。 It's the equivalent of 相当于

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

Finally, RETURN_VALUE : 最后, RETURN_VALUE

Returns with TOS to the caller of the function. 与TOS一起返回给函数的调用者。

The last instruction returns the result of the previous step, which is the reversed str_ . 最后一条指令返回上一步的结果,即反向的str_

Summary 摘要

I see it's very fast, and way more faster than some O(n) solution and also memory saving. 我看到它非常快,并且比某些O(n)解决方案要快得多,并且还节省了内存。

In fact, reversing a list by slicing involves more memory overhead than some other reversal methods in Python. 实际上,与Python中的某些其他逆转方法相比,通过切片逆转列​​表涉及更多的内存开销。 Long story short (and without going down a long rabbit hole), the greater memory overhead occurs because the slicing operation returns a whole list. 长话短说(并且不会陷入漫长的兔子洞),因为切片操作会返回整个列表,所以会产生更大的内存开销。

One alternative method might be: generating an iterator using reversed() , which is usually more performant for memory and time (although, generating a list from this iterator is time-consuming). 一种替代方法可能是:使用reversed()生成迭代器,这通常在内存和时间方面表现更好(尽管从此迭代器生成列表很耗时)。

What algorithm does Python use in this case? 在这种情况下,Python使用什么算法?

To make a long story short: Python loads the variable str , builds a slice(None, None, -1) object, implements str[slice(None, None, -1)] ( source code ), and returns the reversed str . 简而言之:Python加载变量str ,构建slice(None, None, -1)对象,实现str[slice(None, None, -1)]源代码 ),并返回相反的str

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM