阅读本文需要5.2分钟
反转Python字符串的三种主要方法:“切片”,反转迭代和经典的就地反转算法。
在Python中反转字符串的最佳方法是什么?当然,在日常编程中并不经常使用字符串反转,但是这是一个受欢迎的面试问题:
#你有这个: 'TURBO' #而您想要的是: 'OBRUT'
这个问题的一种变化是编写一个函数,该函数检查给定的字符串是否是回文,
def is_palindrome(string): reversed_string = # ??? return string == reversed_string >>> is_palindrome('TACOCAT') True >>> is_palindrome('TURBO') False
显然,我们需要弄清楚如何反转字符串以is_palindrome在Python中实现此功能应该怎么做?
Python的str字符串对象没有内置.reverse()方法,就像其他语言(例如Java或C#)进入Python时所呈现的那样,以下方法将会报错:
>>> 'TURBO'.reverse() Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'str' object has no attribute 'reverse'
这次我们将介绍在Python中反转字符串的三种主要方法以及比较三者之间的性能差距。
第一种:使用“ [::-1]”切片技巧反转Python字符串
字符串遵循Python中的序列协议。并且所有序列都支持一个强大的功能,称为切片。您可以将切片视为方括号索引语法的扩展。
它包括一个特殊情况,其中用“ [::-1]” 切片序列会产生反向副本。因为Python字符串是序列,所以这是获取字符串的反向副本的快速简便的方法:
>>> 'TURBO' [:: - 1 ] 'OBRUT'
可以将此切片表达式写到一个函数中,让代码的作用更加明显:
defreverse_string1(s): """Return a reversed copyof `s`""" returns[::-1] >>>reverse_string1('TURBO') 'OBRUT'
新手第一次遇到列表切片时可能很难理解列表切片。
我觉得使用Python的切片功能来反转字符串是一个不错的解决方案,但是对于初学者来说可能很难理解。
继续…
第二种:使用reversed()和反转Python字符串str.join()
使用reverse()内置的reverse迭代来反转字符串。从而得到一个反向迭代器,然后循环遍历字符串中的元素。例如:
>>>foreleminreversed('TURBO'): ... print(elem) O B R U T
使用reversed()不会修改原始字符串(由于Python中的字符串是不可变的,因此不会起作用。)
到目前为止,所看到的只是如何以相反的顺序遍历字符串的字符。但是,如何使用reverse()函数使用这种方法创建Python字符串的反向副本呢?
看以下例子
>>> ''.join(reversed('TURBO')) 'OBRUT'
此代码段使用该.join()方法将反向迭代产生的所有字符合并到一个新字符串中。
当然,还可以再次将此代码写到单独的函数中创建适当的“反向字符串”。例如:
defreverse_string2(s): """Return a reversed copyof `s`""" return"".join(reversed(s)) >>>reverse_string2('TURBO') 'OBRUT'
它可以清楚地表达正在发生事情的过程,即使是小白也可以直观地了解到正在执行的过程。
第三种:移植到Python的“经典”就地字符串反转算法
这是移植到Python的“经典”就地字符串反转算法。因为Python字符串是不可变的,所以首先需要将输入字符串转换为可变的字符列表,就可以执行就地字符交换:
defreverse_string3(s): """Return a reversed copyof `s`""" chars=list(s) foriinrange(len(s)//2): tmp=chars[i] chars[i]=chars[len(s)-i-1] chars[len(s)-i-1]=tmp return''.join(chars) >>>reverse_string3('TURBO') 'OBRUT'
但是,此方法方非常不实用,它没有发挥Python的优势,并且基本上是C算法的直接移植。哈哈哈,估计大家都不考虑吧
接下来我将对这三种实现进行基准测试。
性能比较
在实现了字符串反转方法之后,我们测试下是三种方法的性能如何
因此,我们开始进行一些基准测试:
>>>importtimeit >>>s='abcdefghijklmnopqrstuvwxyz'*10 >>>timeit.repeat(lambda:reverse_string1(s)) [0.6848115339962533,0.7366074129968183,0.7358982900041156] >>>timeit.repeat(lambda:reverse_string2(s)) [5.514941683999496,5.339547180992668,5.319950777004124] >>>timeit.repeat(lambda:reverse_string3(s)) [48.74324739299482,48.637329410004895,49.223478018000606]
汇总成表格形式:
算法 |
执行时间处理时间 |
慢一点 |
切片 |
0.72秒 |
1倍 |
反向+加入 |
5.39秒 |
7.5倍 |
经典 |
48.87秒 |
67.9倍 |
由此可见,这三种实现之间存在巨大的性能差距。
切片是最快的方法,reversed()比切片慢8倍,而“经典”就地算法在该基准测试中要慢71倍!
总结:
如果您想知道在Python中反转字符串的最佳方法是什么,我的答案是:“取决于情况”。就我个人而言,我喜欢这种reversed()方法,因为它是“自我记录”且相当快。
但是,有一种观点认为,出于性能考虑,应使用快八倍的切片方法……