为字符串实现反向函数的最佳方法是什么?
我自己在这个问题上的经验是学术性的。不过,如果你是一个专业人士,想快速找到答案,可以使用
-1
:
>>> 'a string'[::-1]
'gnirts a'
或者更容易理解(但由于方法名查找和给定迭代器时join形成列表的事实,速度较慢)。
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对象中没有内置的reverse函数。
下面是一些关于python字符串的信息,您应该知道:
-
在蟒蛇中,
字符串是不可变的
. 更改字符串不会修改字符串。它创造了一个新的。
-
字符串是可切片的。对字符串进行切片可以按给定的增量从字符串中的一个点向后或向前到另一个点生成一个新字符串。它们采用切片符号或下标中的切片对象:
string[subscript]
下标通过在大括号中包含冒号来创建切片:
string[start:stop:step]
要在大括号外创建切片,需要创建切片对象:
slice_obj = slice(start, stop, step)
string[slice_obj]
可读的方法:
同时
''.join(reversed('foo'))
是可读的,它需要调用字符串方法,
斯特朗加盟
,在另一个被调用的函数上,这可能相对较慢。让我们把这个放在函数中-我们再回到它:
def reverse_string_readable_answer(string):
return ''.join(reversed(string))
最有效的方法:
使用反向切片要快得多:
'foo'[::-1]
但是,对于不太熟悉切片或原始作者意图的人来说,我们如何才能使其更具可读性和可理解性呢?让我们在下标符号之外创建一个slice对象,给它一个描述性名称,并将其传递给下标符号。
start = stop = None
step = -1
reverse_slice = slice(start, stop, step)
'foo'[reverse_slice]
作为功能实现
要实际将其作为函数实现,我认为它在语义上足够清晰,只需使用一个描述性名称即可:
定义反转字符串(字符串):
返回一个字符串[::-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优化字符串连接,而其他实现
may not
:
…不要依赖于cpython对a+=b或a=a+b形式的语句的就地字符串连接的有效实现。这种优化即使在cpython中也很脆弱(它只适用于某些类型),而且在不使用refcounting的实现中根本不存在。在库的性能敏感部分中,应改用“”join()形式。这将确保在不同实现之间以线性时间进行连接。