Python的str对象没有内置的反向函数。实施此方法的最佳方式是什么?

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


当前回答

下面是如何使用for循环反转字符串:

string = "hello,world"
for i in range(-1,-len(string)-1,-1):
    print (string[i], end=(" "))

其他回答

在python中反转字符串,而不使用reversed()或[::-1]

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

递归方法:

def reverse(s): return s[0] if len(s)==1 else s[len(s)-1] + reverse(s[0:len(s)-1])

例子:

print(reverse("Hello!"))    #!olleH

下面是如何使用for循环反转字符串:

string = "hello,world"
for i in range(-1,-len(string)-1,-1):
    print (string[i], end=(" "))

为字符串实现反向函数的最佳方法是什么?

我自己在这个问题上的经验是学术性的。然而,如果你是一个寻找快速答案的专业人士,请使用一个步骤为-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对象中没有内置的反向函数。

下面是关于Python字符串的一些事情,您应该知道:

在Python中,字符串是不可变的。更改字符串不会修改字符串。它创建了一个新的。字符串是可滑动的。对字符串进行切片可以以给定的增量从字符串中的一个点向后或向前到另一个点创建一个新字符串。它们采用切片符号或下标中的切片对象:字符串[下标]

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

    string[start:stop:step]

要在大括号外创建切片,需要创建切片对象:

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

可读方法:

虽然“”.join(reversed('o'))是可读的,但它需要在另一个被调用的函数上调用字符串方法str.join,这可能相对较慢。让我们把这个放在一个函数中——我们会回到它:

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

最高效的方法:

使用反向切片要快得多:

'foo'[::-1]

但是,我们如何让不太熟悉片段或原作者意图的人更容易阅读和理解呢?让我们在下标表示法之外创建一个切片对象,给它一个描述性名称,并将其传递给下标表示法。

start = stop = None
step = -1
reverse_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中也是脆弱的(它只适用于某些类型),并且在不使用引用计数的实现中根本不存在。在库的性能敏感部分,应改用“”.jjoin()形式。这将确保在各种实现中以线性时间进行连接。

original = "string"

rev_index = original[::-1]
rev_func = list(reversed(list(original))) #nsfw

print(original)
print(rev_index)
print(''.join(rev_func))