2 ответов:
Краткий ответ
Нарезка списков не создает копий объектов в списке; она просто копирует ссылки на них. Это и есть ответ на заданный вопрос.
Длинный ответ
Тестирование на изменяемые и неизменяемые значения
Во-первых, давайте проверим основное утверждение. Мы можем показать, что даже в случае неизменяемых объектов, таких как целые числа, копируется только ссылка. Вот три различных целочисленных объекта, каждый с тем же самым значение:Они имеют одинаковое значение, но вы можете видеть, что это три различных объекта, потому что они имеют разные>>> a = [1000 + 1, 1000 + 1, 1000 + 1]ids:>>> map(id, a) [140502922988976, 140502922988952, 140502922988928]Когда вы их срезаете, ссылки остаются теми же. Новые объекты не были созданы:
>>> b = a[1:3] >>> map(id, b) [140502922988952, 140502922988928]Использование различных объектов с одинаковым значением показывает, что процесс копирования не утруждает себяинтернированием - он просто непосредственно копирует ссылки.
Тестирование с изменяемыми значениями дает то же самое результат:
>>> a = [{0: 'zero', 1: 'one'}, ['foo', 'bar']] >>> map(id, a) [4380777000, 4380712040] >>> map(id, a[1:] ... ) [4380712040]Проверка оставшихся накладных расходов памяти
Конечно, ссылки сами копируются. Каждый из них стоит 8 байт на 64-разрядной машине. И каждый список имеет свой собственный объем памяти 72 байта:
>>> for i in range(len(a)): ... x = a[:i] ... print('len: {}'.format(len(x))) ... print('size: {}'.format(sys.getsizeof(x))) ... len: 0 size: 72 len: 1 size: 80 len: 2 size: 88, как Джо Pinsonault напоминает нам, что накладные расходы суммируются. А сами целочисленные объекты не очень велики - они в три раза больше ссылок. Таким образом, это экономит вам некоторую память в абсолютном смысле, но асимптотически, это было бы неплохо иметь возможность иметь несколько списков, которые являются "представлениями" в одной и той же памяти.
Сохранение памяти с помощью представлений
К сожалению, Python не предоставляет простого способа создания объектов, которые являются "представлениями" в списки. Или, возможно, я должен сказать "к счастью"! Это означает, что вам не нужно беспокоиться о том, откуда взялся срез; изменения в оригинале не повлияют на срез. В целом, это значительно облегчает рассуждения о поведении программы.
Если вы действительно хотите сэкономить память работая с представлениями, рассмотрите возможность использования массивов
numpy. При срезе массиваnumpyпамять делится между срезом и оригиналом:Что происходит, когда мы модифицируем>>> a = numpy.arange(3) >>> a array([0, 1, 2]) >>> b = a[1:3] >>> b array([1, 2])aи снова смотрим наb?Но это означает, что вы должны быть уверены, что, изменяя один объект, вы случайно не изменяете другой. Это компромисс, когда вы используете>>> a[2] = 1001 >>> b array([ 1, 1001])numpy: меньше работы для компьютера и больше работы для программиста!
В зависимости от того, что вы делаете, вы можете использовать
islice.Поскольку он работает через итерацию, он не будет создавать новые списки, а вместо этого будет просто создавать итераторы, которые
yieldэлементы из исходного списка, как это требуется для их диапазонов.
Comments