Насколько эффективно извлечение подстроки Python?

У меня есть все содержимое текстового файла (не менее нескольких КБ) в строке myStr.

Будет ли следующий код создавать копию строки (за вычетом первого символа) в памяти?

myStr = myStr[1:]

Я надеюсь, что это просто относится к другому месту в том же внутреннем буфере. Если нет, есть ли более эффективный способ сделать это?

Спасибо!

Примечание. Я использую Python 2.5.


person Cameron    schedule 16.03.2010    source источник
comment
@Glenn: Спасибо за редактирование. Я всегда забываю вычитывать заголовок!   -  person Cameron    schedule 16.03.2010
comment
@Mike: Ха, наверное, я слишком оптимизирую. Загружаемые файлы могут потенциально быть большими (теоретически), но в настоящее время самый большой размер составляет 8 КБ :-)   -  person Cameron    schedule 17.03.2010
comment
Несколько КБ — это крошечная сумма, но если вы используете такой алгоритм, как [s[0:n] for n in range(0, len(s))], вы получите O(n^2), тогда как нарезка на месте даст вам O(n). Очевидно, вы всегда можете обойти это; это просто дополнительная работа.   -  person Glenn Maynard    schedule 19.03.2010


Ответы (4)


По крайней мере, в версии 2.6 срезы строк всегда являются новыми выделениями; string_slice() вызывает PyString_FromStringAndSize(). Он не использует повторно память, что немного странно, поскольку с инвариантными строками это должно быть относительно легко сделать.

За исключением буферного API (который вам, вероятно, не нужен), нет более эффективного способа выполнить эту операцию.

person Glenn Maynard    schedule 16.03.2010
comment
Спасибо за информацию. На самом деле я использую Python 2.5 (я обновил свой вопрос), но сомневаюсь, что это делается по-другому. Думаю, мне просто придется смириться с дублированием (мне действительно нужно удалить этот символ). - person Cameron; 16.03.2010
comment
Разве вы не можете просто прочитать первый символ из файла и не присваивать его строке для начала? Смотрите мой ответ, приходящий на мгновение. изменить: вместо этого см. ответ Бенсона. - person jcdyer; 16.03.2010

Как и в большинстве языков со сборкой мусора, строки создаются так часто, как это необходимо, что происходит очень часто. Причина этого в том, что описанное отслеживание подстрок затруднит сборку мусора.

Каков фактический алгоритм, который вы пытаетесь реализовать. Возможно, мы могли бы дать вам совет о том, как добиться лучших результатов, если бы мы знали об этом немного больше.

Что касается альтернативы, что вам действительно нужно сделать? Не могли бы вы использовать другой способ взглянуть на проблему, например просто сохранить целочисленный индекс в строке? Не могли бы вы использовать array.array('u')?

person SingleNegationElimination    schedule 16.03.2010
comment
Я удаляю спецификацию из декодированного файла UTF-8 в памяти, затем отправляю содержимое этого файла в механизм шаблонов (Jinja2), а затем записываю результат в ответ HTML. Я только что нашел способ сделать это только один раз для каждого файла шаблона, так что это больше не проблема :-) - person Cameron; 16.03.2010

Одно (хотя и немного хакерское) решение будет примерно таким:

f = open("test.c")
f.read(1)
myStr = f.read()
print myStr

Он пропустит первый символ, а затем прочитает данные в вашу строковую переменную.

person Benson    schedule 16.03.2010
comment
На самом деле, это будет считывать первый байт, не обязательно первый символ. В файле с кодировкой utf-8 только 128 символов US-ASCII закодированы в одном байте. - person tgray; 16.03.2010
comment
Итак, прочитайте первую строку, преобразуйте в юникод, а затем удалите первый символ. Действуйте более или менее так, как описано выше, конвертируя в Unicode по ходу дела. Если вы не конвертируете, вы имеете дело с байтами. - person jcdyer; 16.03.2010
comment
Я бы использовал эту технику, но в то время, когда я читаю ее из файла, я не знаю, следует ли сохранять спецификацию или нет. Когда я позже извлекаю содержимое (из БД), я сразу возвращаю весь файл. Версия вашей техники уже была представлена ​​мне в ответе на другой (связанный) вопрос, который я задал ранее: stackoverflow .com/questions/2456380/ - person Cameron; 17.03.2010
comment
Всегда используйте диспетчер контекста при работе с файлами, т.е. with open("test.c") as f: - person Mike Graham; 17.03.2010
comment
@Mike: Я бы так и сделал, но он сказал, что использует 2.5, и я не хотел возиться с мусором from future import with_statement. - person Benson; 19.03.2010
comment
@ Бенсон, это не мусор; это делает ваш код правильным. Если бы он использовал Python до версии 2.5, я бы сказал, что close должен находиться внутри блока finally. - person Mike Graham; 19.03.2010
comment
Возможно, вы вообще не читаете из файла; есть много (хотя и нечастых) случаев, когда возможность бесплатно создавать срезы строк упрощает получение эффективного алгоритма. - person Glenn Maynard; 19.03.2010

В зависимости от того, что вы делаете, itertools.islice может быть подходящим решением для эффективного использования памяти (если оно понадобится).

person Mike Graham    schedule 16.03.2010
comment
Круто, я даже не знал, что такой модуль существует! - person Cameron; 17.03.2010
comment
Тогда хорошая находка! — itertools всегда пригодится. - person Mike Graham; 17.03.2010