实现字符串反向函数的最佳方法是什么?
我自己对这个问题的经验是学术性的。但是,如果您是一个寻找快速答案的专家,请使用-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对象中没有内置的反向函数。
下面是关于Python字符串的几件事,您应该知道:在Python里,字符串是不可变的。。更改字符串不会修改字符串。它创造了一个新的。
字符串是可切分的。将字符串切片给您一个新的字符串,从字符串中的一个点,向后或向前,通过给定的增量从另一个点到另一个点。它们在下标中采用片表示法或片对象:string[subscript]
下标通过在大括号中包含一个冒号来创建一个片:string[start:stop:step]
要在大括号之外创建一个片,您需要创建一个片对象:slice_obj = slice(start, stop, step)
string[slice_obj]
可读的方法:
当''.join(reversed('foo'))是可读的,它需要调用字符串方法,str.join,对另一个称为函数,这可能比较慢。让我们把它放在一个函数里-我们会回到它:def reverse_string_readable_answer(string):
return ''.join(reversed(string))
最具表现力的方法:
使用反向切片要快得多:'foo'[::-1]
但是,我们如何才能让不太熟悉切片或原作者意图的人更容易阅读和理解呢?让我们在下标符号之外创建一个片对象,给它一个描述性名称,并将它传递给下标符号。start = stop = Nonestep = -1reverse_slice = slice(start, stop, step)'foo'[reverse_slice]
实现为功能
要将其实际实现为一个函数,我认为使用描述性名称在语义上是足够清楚的:def reversed_string(a_string):
return a_string[::-1]
使用方法很简单:reversed_string('foo')
你的老师可能想要的是:
如果你有一个指导员,他们可能希望你从一个空字符串开始,并从旧的字符串中建立一个新的字符串。您可以使用纯语法和文字来使用while循环来完成这一任务: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
理论上这很糟糕,因为,记住,字符串是不可变的。-所以每次当你在你的new_string,从理论上讲,它每次都会创建一个新字符串!但是,CPython知道如何在某些情况下优化这一点,而这种情况就是其中之一。
最佳做法
理论上更好的做法是把你的子串收集到一个列表中,然后加入它们: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可以优化字符串连接。
计时
以下是时间安排:>>> 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优化字符串连接,而其他实现则优化。不可能:..不要依赖CPython对a+=b或a=a+b形式的语句有效地实现就地字符串连接。即使在CPython中,这种优化也是脆弱的(它只适用于某些类型),而且在不使用重新计算的实现中根本不存在。在库的性能敏感部分,应该使用‘.join()表单。这将确保在各种实现中以线性时间进行级联。