在Python中反转一个string

Python的str对象没有内置的reverse函数。 实施这种方法的最好方法是什么?

如果提供一个非常简洁的答案,请详细说明其效率。 例如, str对象是否转换为不同的对象等

怎么样:

 >>> 'hello world'[::-1] 'dlrow olleh' 

这是扩展的片语法。 它通过执行[begin:end:step] – 通过将begin和endclosures并指定-1的一个步骤,它将反转一个string。

保罗的s[::-1]是最快的; 一个较慢的方法(也许更可读,但这是有争议的)是''.join(reversed(s))

实现string反转函数的最好方法是什么?

我对这个问题的经验是学术的。 然而,如果你是一个寻找快速答案的专业人士,请使用一个按-1递增的片段:

 >>> 'a string'[::-1] 'gnirts a' 

或更可读(但由于方法名称查找和连接形成一个列表给予一个迭代器的事实较慢), str.join

 >>> ''.join(reversed('a string')) 'gnirts a' 

或为了可读性和可重用性,把切片放在一个函数中

 def reversed_string(a_string): return a_string[::-1] 

接着:

 >>> reversed_string('a_string') 'gnirts_a' 

更长的解释

如果您对学术论文感兴趣,请继续阅读。

Python的str对象中没有内置的反转函数。

下面是关于Pythonstring的一些你应该知道的事情:

  1. 在Python中, string是不可变的 。 更改string不会修改string。 它创造了一个新的。

  2. string是可切片的。 切一个string给你一个新的string,从string中的一个点,向后或向前,到另一个点,以给定的增量。 他们在下标中使用切片符号或切片对象:

     string[subscript] 

下标通过在大括号中包含冒号来创build切片:

  string[start:stop:step] 

要在花括号之外创build片,您需要创build一个片对象:

  slice_obj = slice(start, stop, step) string[slice_obj] 

可读的方法:

虽然''.join(reversed('foo'))是可读的,但它需要在另一个被调用的函数上调用一个string方法str.join ,这个方法可能相对较慢。 让我们把它放在一个函数中 – 我们将回到它:

 def reverse_string_readable_answer(string): return ''.join(reversed(string)) 

最高性能的方法:

使用反转片的速度要快得多:

 'foo'[::-1] 

但是,对于那些不太熟悉切片或原作者意图的人,我们怎么能使这个更易读易懂呢? 让我们在下标符号之外创build一个切片对象,给它一个描述性名称,并将其传递给下标符号。

 start = stop = None step = -1 reverse_slice = slice(start, stop, step) 'foo'[reverse_slice] 

按function实施

要真正实现这个作为一个函数,我认为它在语义上足够清楚,只需使用一个描述性的名称:

 def reversed_string(a_string): return a_string[::-1] 

用法很简单:

 reversed_string('foo') 

你的老师可能想要什么:

如果你有一个教练,他们可能希望你从一个空的string开始,并从旧的stringbuild立一个新的string。 你可以用纯循环语法和文字来做到这一点:

 def reverse_a_string_slowly(a_string): new_string = '' index = len(a_string) while index: index -= 1 # index = index - 1 new_string += a_string[index] # new_string = new_string + character return new_string 

这在理论上是不好的,因为记住, string是不可变的 – 所以每次看起来你要在新string上附加一个字符时,理论上每次都会创build一个新的string! 然而,CPython知道如何在某些情况下优化这个,其中这个微不足道的情况就是这样。

最佳实践

从理论上讲,更好的办法是在列表中收集你的子string,然后join:

 def reverse_a_string_more_slowly(a_string): new_strings = [] index = len(a_string) while index: index -= 1 new_strings.append(a_string[index]) return ''.join(new_strings) 

但是,正如我们将在下面的CPython中看到的那样,这实际上需要更长的时间,因为CPython可以优化string连接。

计时

这里是时间:

 >>> a_string = 'amanaplanacanalpanama' * 10 >>> min(timeit.repeat(lambda: reverse_string_readable_answer(a_string))) 10.38789987564087 >>> min(timeit.repeat(lambda: reversed_string(a_string))) 0.6622700691223145 >>> min(timeit.repeat(lambda: reverse_a_string_slowly(a_string))) 25.756799936294556 >>> min(timeit.repeat(lambda: reverse_a_string_more_slowly(a_string))) 38.73570013046265 

CPython优化string连接,而其他实现可能不会 :

…不要依赖于CPython有效地实现以a + = b或a = a + bforms的语句的就地string连接。 即使在CPython中,这种优化也很脆弱(它只适用于某些types),在不使用refcounting的实现中完全不存在。 在库的性能敏感部分,应该使用''.join()表单来代替。 这将确保串联在各种实现中以线性时间发生。

快速回答(TL; DR)

 ### example01 ------------------- mystring = 'coup_ate_grouping' backwards = mystring[::-1] print backwards ### ... or even ... mystring = 'coup_ate_grouping'[::-1] print mystring ### result01 ------------------- ''' gnipuorg_eta_puoc ''' 

详细的答案

背景

提供这个答案是为了解决@odigity的以下问题:

哇。 保罗先生提出的解决办法让我感到震惊,但是当我读到第一条评论时,我感到恐惧:“这是非常诡异的,好的工作! 我感到非常不安,这样一个明亮的社会认为使用这种神秘的方法来做这么基本的事情是一个好主意。 为什么不是只是s.reverse()?

问题

  • 上下文
    • Python 2.x
    • Python 3.x
  • 场景:
    • 开发人员想要转换一个string
    • 转换是颠倒所有字符的顺序

  • example01使用扩展切片符号生成所需的结果。

陷阱

  • 开发人员可能会期望像string.reverse()
  • 新的开发人员可能无法阅读本地惯用(又称“ pythonic ”)解决scheme
  • 开发人员可能会试图实现他或她自己的string.reverse()版本以避免切片符号。
  • 切片符号的输出在某些情况下可能是违反直觉的:
    • 例如参见实例02
      • print 'coup_ate_grouping'[-4:] ## => 'ping'
      • 相比
      • print 'coup_ate_grouping'[-4:-1] ## => 'pin'
      • 相比
      • print 'coup_ate_grouping'[-1] ## => 'g'
    • 索引[-1]的不同结果可能会导致一些开发者closures

合理

Python有一个特殊的情况要注意:一个string是一个可迭代的types。

排除string.reverse()方法的一个基本原理是让python开发人员能够利用这种特殊情况的力量。

简而言之,这只是意味着string中的每个单独的字符都可以很容易地作为一个顺序数组元素的一部分进行操作,就像其他编程语言中的数组一样。

要理解这是如何工作的,查看example02可以提供一个很好的概述。

Example02

 ### example02 ------------------- ## start (with positive integers) print 'coup_ate_grouping'[0] ## => 'c' print 'coup_ate_grouping'[1] ## => 'o' print 'coup_ate_grouping'[2] ## => 'u' ## start (with negative integers) print 'coup_ate_grouping'[-1] ## => 'g' print 'coup_ate_grouping'[-2] ## => 'n' print 'coup_ate_grouping'[-3] ## => 'i' ## start:end print 'coup_ate_grouping'[0:4] ## => 'coup' print 'coup_ate_grouping'[4:8] ## => '_ate' print 'coup_ate_grouping'[8:12] ## => '_gro' ## start:end print 'coup_ate_grouping'[-4:] ## => 'ping' (counter-intuitive) print 'coup_ate_grouping'[-4:-1] ## => 'pin' print 'coup_ate_grouping'[-4:-2] ## => 'pi' print 'coup_ate_grouping'[-4:-3] ## => 'p' print 'coup_ate_grouping'[-4:-4] ## => '' print 'coup_ate_grouping'[0:-1] ## => 'coup_ate_groupin' print 'coup_ate_grouping'[0:] ## => 'coup_ate_grouping' (counter-intuitive) ## start:end:step (or start:end:stride) print 'coup_ate_grouping'[-1::1] ## => 'g' print 'coup_ate_grouping'[-1::-1] ## => 'gnipuorg_eta_puoc' ## combinations print 'coup_ate_grouping'[-1::-1][-4:] ## => 'puoc' 

结论

理解python如何使用切片符号的认知负担对于一些不想花太多时间来学习语言的使用者和开发者来说确实是太多了。

尽pipe如此,一旦理解了基本原则,这种方法在固定string操作方法上的力量就可以相当有利。

对于那些认为不然的人来说,还有其他的方法,比如lambda函数,迭代器或简单的一次函数声明。

如果需要的话,开发人员可以实现自己的string.reverse()方法,但是理解python这个方面的基本原理是很好的。

也可以看看

  • 备用简单的方法
  • 备用简单的方法
  • 切片符号的替代解释

一个更难以理解的方式来看待它将是:

 string = 'happy' print(string) 

'快乐'

 string_reversed = string[-1::-1] print(string_reversed) 

“帕”

英文[-1 :: – 1]的内容如下:

“从-1开始,一路走,步-1”

在python中反转string而不使用反转()或[:: – 1]

 def reverse(test): n = len(test) x="" for i in range(n-1,-1,-1): x += test[i] return x 

这是一个不寻常的:

 def reverse(text): r_text = '' index = len(text) - 1 while index >= 0: r_text += text[index] #string canbe concatenated index -= 1 return r_text print reverse("hello, world!") 
 def reverse(input): return reduce(lambda x,y : y+x, input) 

这是一个没有[::-1]reversed (用于学习的目的):

 def reverse(text): new_string = [] n = len(text) while (n > 0): new_string.append(text[n-1]) n -= 1 return ''.join(new_string) print reverse("abcd") 

你可以使用+=连接string,但join()更快。

另一种select是(效率不高!只是为了展示Python的多样性,有很多可能的解决scheme!):使用list()函数将string转换为列表。 列表值是一个可变的数据types。 因此,我们可以使用reverse()方法反转列表中的对象。 然后我们使用带有空分隔符的列表连接方法将列表转换回string:

 >>> s = 'hello world' >>> s 'hello world' >>> t = list(s) # convert to list >>> t ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'] >>> t.reverse() # reverse method of list >>> t ['d', 'l', 'r', 'o', 'w', ' ', 'o', 'l', 'l', 'e', 'h'] >>> s = ''.join(t) # convert to string >>> s 'dlrow olleh' 

这里简单地说:

打印“loremipsum”[ – 1 :: – 1]

有些在逻辑上:

 def str_reverse_fun(): empty_list = [] new_str = 'loremipsum' index = len(new_str) while index: index = index - 1 empty_list.append(new_str[index]) return ''.join(empty_list) print str_reverse_fun() 

输出:

muspimerol

 s = 'hello' ln = len(s) i = 1 while True: rev = s[ln-i] print rev, i = i + 1 if i == ln + 1 : break 

输出:

 olleh 

当然,在Python中,你可以做很花哨的1行东西。 🙂
这是一个简单,全面的解决scheme,可以使用任何编程语言。

 def reverse_string(phrase): reversed = "" length = len(phrase) for i in range(length): reversed += phrase[length-1-i] return reversed phrase = raw_input("Provide a string: ") print reverse_string(phrase) 

您可以使用带有列表综合function的反转函数。 但是我不明白为什么这个方法在python 3中被淘汰了,是不必要的。

 string = [ char for char in reversed(string)]