Строки Python неизменяемы, поэтому почему s.split () возвращает список новых строк

CPython реализацию CPython кажется, что возвращаемое значение строки split() представляет собой список недавно выделенных строк. Однако, поскольку строки являются неизменными, кажется, что можно было сделать подстроки из исходной строки, указав на смещения.

Я правильно понимаю текущее поведение CPython? Есть ли причины для отказа от этой оптимизации пространства? Одна из причин, о которой я могу думать, заключается в том, что родительскую строку нельзя освободить до тех пор, пока все ее подстроки не будут.

3 Solutions collect form web for “Строки Python неизменяемы, поэтому почему s.split () возвращает список новых строк”

В текущей реализации CPython строки подсчитываются; предполагается, что строка не может содержать ссылки на другие объекты, потому что строка не является контейнером. Это означает, что сборку мусора не нужно проверять или отслеживать поверх строковых объектов (потому что они полностью покрыты подсчетом ссылок). Но на самом деле это хуже: в старых версиях Python не было трассировочного сборщика мусора ; GC был новым в версии 2.0 . До этого любой циклический мусор просто просачивался.

Компетентно реализованный алгоритм подстроки к смещению не должен формировать циклы. Поэтому теоретически циклический сборщик мусора не является обязательным условием для этого. Однако, поскольку мы делаем подсчет ссылок вместо трассировки, дочерние объекты становятся ответственными за Py_DECREF() своих родительских объектов в конце срока службы. В противном случае родительский утечка. Это означает, что вы не можете просто вытащить всю строку в свободный список, когда он достигнет конца жизни; вы должны проверить, является ли это подстрокой, а ветвление потенциально дорого . Python был исторически разработан для выполнения строковой обработки (например, Perl, но с более сильным синтаксисом), что означает создание и уничтожение множества строк. Кроме того, все имена переменных внутренне хранятся как строки, поэтому даже если пользователь не выполняет строчную обработку, интерпретатор. Замедление процесса освобождения строк даже незначительно может серьезно повлиять на производительность.

Без хрустального шара я не могу сказать вам, почему CPython делает это именно так. Однако есть некоторые причины, по которым вы можете сделать это.

Проблема в том, что небольшая строка может содержать ссылку на гораздо больший массив поддержки. Например, предположим, что я прочитал в файле журнала доступа HTTP 8 ГБ, чтобы проанализировать, какие пользовательские агенты чаще всего fp.read() к моему файлу, и я делаю это только с помощью fp.read() а затем запускаю регулярное выражение на весь файл одновременно, по одной строке за раз.

Я хочу знать о 10 самых распространенных пользовательских агентах, поэтому я держу это в списке.

Затем я хочу сделать тот же анализ для 100 других файлов, чтобы узнать, как изменились с течением времени лучшие 10 пользовательских агентов. Boom! Моя программа пытается использовать 800 ГБ памяти и убивается. Зачем? Как мне отладить это?

Java использовал этот метод обмена до Java 7, поэтому применяются те же рассуждения. См. Java 7 String – сложность подстроки и JDK-4513622: (str) сохранение подстроки поля предотвращает GC для объекта .

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

CPython внутренне использует NUL-завершенные строки в дополнение к хранению длины. Это очень ранний выбор дизайна, представленный с самой первой версии Python, и по-прежнему верен в последней версии.

Вы можете видеть это в Include / unicodeobject.h, где PyASCIIObject говорит «представление wchar_t (завершение с нулевой отметкой)», а PyCompactUnicodeObject говорит «представление UTF-8 (завершение с нулевой отметкой)». (Последние реализации CPython выбирают из одного из 4 типов исходных строк, в зависимости от потребностей кодирования Unicode.)

Многие модули расширения Python ожидают завершенную строку NUL. Было бы сложно реализовать подстроки в виде срезов в большую строку и сохранить низкоуровневый C API. Это невозможно, поскольку это можно сделать с помощью доступа к копированию на C-API. Или Python может потребовать, чтобы все авторы расширений использовали новый API-интерфейс, совместимый со слоями. Но эта сложность не стоит, учитывая проблемы, найденные на опыте других языков, которые реализуют ссылки на сублиты, как описано Dietrich Epp.

Я мало вижу в ответе Кевина, который применим к этому вопросу. Решение не имело ничего общего с отсутствием круговой сборки мусора перед Python 2.0 и не могло. Подрезные срезы реализуются с ациклической структурой данных. «Компетентно-реализованный» не является обязательным требованием, поскольку для превращения его в циклическую структуру данных может потребоваться порочная некомпетентность или злоба.

Кроме того, в deallocator не было бы лишних расходов на ветви. Если исходная строка была одного типа, а подстрока разрезала другой тип, диспетчер стандартного типа Python автоматически использовал бы правильный деллалокатор без дополнительных накладных расходов. Даже если бы существовала дополнительная ветка, мы знаем, что накладные расходы на ветвление в этом случае не являются «дорогостоящими». Python 3.3 (из-за PEP 393) имеет эти 4 back-end типа Unicode и решает, что делать на основе ветвления. Доступ к строкам происходит гораздо чаще, чем освобождение, поэтому любые издержки наложения из-за ветвления будут потеряны в шуме.

В основном это верно, что в CPython «имена переменных внутренне хранятся как строки». (Исключение состоит в том, что локальные переменные хранятся в виде индексов в локальном массиве.) Однако эти имена также интернированы в глобальный словарь, используя PyUnicode_InternInPlace (). Следовательно, нет накладных расходов на освобождение, поскольку эти строки не освобождаются, за исключением случаев, связанных с динамической отправкой с использованием неинтерминированных строк, например, через getattr ().

  • Использование! S vs.: s для форматирования строки в Python
  • Форматирование строки Python - старое `%` vs new `str.format`
  • Строка печати Python в текстовый файл
  • Как обрабатывать \ 2 в пути Windows с помощью Python?
  • преобразование строки unicode в python
  • Лучший способ преобразовать строку в байты в Python 3?
  • Как разобрать строку, представляющую вложенный список, в фактический список?
  • Импорт текстового файла дает ошибку
  • Сплит RSS RSS-строка с использованием Python
  • Как записать строковый столбец строки данных python, если он имеет отсутствующие значения?
  • Как получить только арабские тексты из строки, используя регулярное выражение?
  •  
    Interesting Posts for Van-Lav

    Рендеринг HTML в web.py

    Передача операции вдоль определенной оси в python

    Как распознать специальный символ eol, когда я его вижу, используя Python?

    Python 3 urllib создает TypeError: данные POST должны быть байтами или итерируемыми байтами. Это не может быть типа str

    Как распечатать содержимое моих настроек в оболочке django?

    передача экземпляров классов C ++ в python с boost :: python

    Сравнение двух различий отчетов в python

    Измените переменную сервера из потока клиента (threading, python)

    Панды: множественные гистограммы категориальных данных

    исключение для уведомления о том, что подкласс должен реализовывать метод в python

    Почему группа «не захватывающих» регулярных выражений не работает

    Отображение символа Юникода

    Анализ файлов журнала Apache

    удалить последнюю строку STDOUT в Python

    Невозможно очистить определенные значения веб-сайта с помощью регулярного выражения

    Python - лучший язык программирования в мире.