Каков наилучший способ реализации обратной функции для строк?
Мой собственный опыт в этом вопросе академический. Тем не менее, если вы профессионал и ищете быстрый ответ, используйте фрагмент с шагом -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'
Более подробное объяснение
Если вы заинтересованы в академической экспозиции, пожалуйста, продолжайте читать.
В объекте str Python нет встроенной обратной функции.
Вот пара вещей о строках 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 = 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 (она работает только для некоторых типов) и совсем не присутствует в реализациях, которые не используют пересчет. В чувствительных к производительности частях библиотеки следует использовать форму '' .join (). Это будет гарантировать, что конкатенация происходит в линейное время в разных реализациях.