Python List против Array - когда использовать?


375

Если вы создаете одномерный массив, вы можете реализовать его в виде списка или использовать модуль «массив» в стандартной библиотеке. Я всегда использовал списки для 1d массивов.

По какой причине или обстоятельству я хотел бы использовать вместо этого модуль массива?

Это для оптимизации производительности и памяти, или я упускаю что-то очевидное?

Ответы:


438

По сути, списки Python очень гибкие и могут содержать совершенно разнородные произвольные данные, и к ним можно очень эффективно добавлять в амортизированное постоянное время . Если вам нужно сокращать и расширять свой список эффективно и без лишних хлопот, они - путь. Но они используют намного больше места, чем массивы C .

array.arrayТипа, с другой стороны, это всего лишь тонкая оболочка на массивах C. Он может содержать только однородные данные одного типа, поэтому он использует только sizeof(one object) * lengthбайты памяти. В основном, вы должны использовать его, когда вам нужно представить массив C расширению или системному вызову (например, ioctlили fctnl).

array.arrayтакже является разумным способом представления изменяемой строки в Python 2.x ( array('B', bytes)). Тем не менее, Python 2.6+ и 3.x предлагает изменяемую строку байтов какbytearray .

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

Короче говоря : array.arrayполезно, когда вам нужен однородный массив данных C по причинам, отличным от математического .


9
Имеет ли numpy.ndarray тот же объем памяти, что и array.array?
— Гордон Бин

6
@ Гордон, он должен быть очень похожим в случае большого непрерывного массива: им обоим потребуется sizeof(element)× (количество элементов) байтов, плюс небольшой фиксированный заголовок для служебных данных. Тем не менее, ndarray имеет некоторые расширенные опции для работы с разрозненными и разреженными массивами, и я думаю, что некоторые подключаемые стратегии для выделения памяти для больших массивов ... некоторые из этих расширенных функций сделают его менее оперативным, в то время как другие улучшат производительность, используя больше Память.
— Дэн Ленски

Также полезно, когда возникает проблема с памятью, например, при программировании микроконтроллеров с помощью микропифона
— janscas

Можно искать i-й элемент массива за постоянное время, тогда как в связанном списке он принимает порядок 'n' в худшем случае. Каково время поиска i-го элемента в списке Python?
— Nithish Inpursuit Ofhappiness

7
@NithishInpursuitOfhappiness, список Python не является связанным списком. Внутри он представлен в виде массива и имеет те же характеристики сложности времени, что и ArrayList в Java. Таким образом, получение и установка i-го элемента списка Python занимает постоянное время . Добавление элемента в список Python занимает амортизированное постоянное время, поскольку размер массива удваивается, когда ему не хватает места. Вставка элемента в середину списка Python или удаление из него занимает O (n) времени, потому что элементы должны быть смещены. Для справки: wiki.python.org/moin/TimeComplexity
— geofflee

66

Почти во всех случаях нормальный список является правильным выбором. Модуль массивов больше похож на тонкую оболочку над массивами Си, которая дает вам строго типизированные контейнеры (см. Документы ), с доступом к более C-подобным типам, таким как подписанные / неподписанные короткие или двойные, которые не являются частью встроенного в типах. Я бы сказал, использовать модуль массива, только если он вам действительно нужен, во всех остальных случаях придерживайтесь списков.


3
Возможно, никогда не использовал это действительно хотя, но было бы интересно выполнить некоторые микро тесты.
— Андре

13
На самом деле, я сделал быстрый тест - я рассчитал время суммирования списка с 100M записями и того же теста с соответствующим массивом, и этот список был на 10% быстрее.
— Мо

38
Списки быстрее, потому что операции с «необработанными» данными массива должны постоянно создавать и уничтожать объекты Python при чтении или записи в массив.
— Цот

7
@Moe, как я указывал в моем ответе выше, Python встроенный arrayв не предназначен для выполнения математика . Если вы попытаетесь использовать NumPy ndarrayдля суммирования массива из 10 ^ 8 чисел, он будет полностью listудален. У @tzot есть правильное представление о том, почему встроенная система arrayработает медленно по математике.
— Дэн Ленски

2
Я только что проверил, NumPy 86,6x быстрее на моей машине.
— Отметить

53

Модуль массива - это одна из тех вещей, в которых вы, вероятно, не нуждаетесь, если не знаете, зачем его использовать (и обратите внимание, что я не пытаюсь сказать это снисходительно!) , Большую часть времени модуль массива используется для взаимодействия с кодом Си. Чтобы дать вам более прямой ответ на ваш вопрос о производительности:

Массивы более эффективны, чем списки для некоторых целей. Если вам нужно выделить массив, который, как вы ЗНАЕТЕ, не изменится, тогда массивы могут быть быстрее и использовать меньше памяти. GvR имеет анекдот по оптимизации, в котором модуль массива оказывается победителем (долго читал, но оно того стоит).

С другой стороны, одна из причин, по которой списки занимают больше памяти, чем массивы, заключается в том, что python выделит несколько дополнительных элементов, когда все выделенные элементы будут использованы. Это означает, что добавление элементов в списки происходит быстрее. Так что, если вы планируете добавлять элементы, список - это путь.

TL; DR Я бы использовал массив, только если у вас была исключительная потребность в оптимизации или вам нужно взаимодействовать с кодом C (и вы не можете использовать pyrex ).


1
+1 за конкретный пример и упоминание скоростной выгоды. Главный ответ заставил меня задуматься: «Есть ли компромисс между временем и памятью?» и "Есть ли смысл в этом, который не очень эзотерический случай с нехваткой памяти?"
— leewz

@leewz точно, это следует рассматривать как ответ.
— Гаури Шанкар Бадола

21

Это компромисс!

плюсы каждого:

список

  • гибкий
  • может быть неоднородным

массив (напр .: массив numpy)

  • массив равномерных значений
  • гомогенный
  • компактный (по размеру)
  • эффективный (функциональность и скорость)
  • удобный

2
вопрос относится к массиву модуля в python; не numy массивы. У них нет много плюсов, кроме эффективности размера. Они не быстрее.
— NONONONONO

14

Насколько я понимаю, массивы хранятся более эффективно (то есть как непрерывные блоки памяти по сравнению с указателями на объекты Python), но я не знаю о какой-либо выигрыш в производительности. Кроме того, с массивами вы должны хранить примитивы одного типа, тогда как списки могут хранить что угодно.


8

Массивы стандартной библиотеки полезны для двоичного ввода-вывода, например, для преобразования списка целых чисел в строку для записи, скажем, в волновой файл. Тем не менее, как уже отмечали многие, если вы собираетесь делать какую-то реальную работу, то вам следует рассмотреть возможность использования NumPy.


6

Если вы собираетесь использовать массивы, рассмотрите пакеты numpy или scipy, которые дают вам массивы с большей гибкостью.


5

Массив может использоваться только для определенных типов, тогда как списки могут использоваться для любого объекта.

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

Массивы также более эффективны для некоторых численных расчетов.


4
Встроенные массивы Python не эффективны с точки зрения производительности, а только с точки зрения памяти.
— Цот

Есть случаи, когда массивы более эффективны с точки зрения обработки. Смотрите мой пост ниже: stackoverflow.com/questions/176011/…
— Джейсон Бейкер

0

Важное различие между массивом numpy и списком состоит в том, что срезы массива являются представлениями исходного массива. Это означает, что данные не копируются, и любые изменения в представлении будут отражены в исходном массиве.


0

Этот ответ подытожит почти все запросы о том, когда использовать List и Array:

  1. Основное различие между этими двумя типами данных заключается в операциях, которые вы можете выполнять над ними. Например, вы можете разделить массив на 3, и он разделит каждый элемент массива на 3. То же самое нельзя сделать со списком.

  2. Список является частью синтаксиса python, поэтому его не нужно объявлять, в то время как вы должны объявить массив перед его использованием.

  3. Вы можете хранить значения разных типов данных в списке (разнородных), тогда как в массиве вы можете хранить значения только одного и того же типа данных (однородных).

  4. Массивы, обладающие большими функциональными возможностями и быстрыми, широко используются для арифметических операций и для хранения большого объема данных - по сравнению со списком.

  5. Массивы занимают меньше памяти по сравнению со списками.


0

Что касается производительности, вот некоторые цифры, сравнивающие списки, массивы и пустые массивы Python (все с Python 3.7 на Macbook Pro 2017 года). Конечным результатом является то, что список python является самым быстрым для этих операций.

# Python list with append()
np.mean(timeit.repeat(setup="a = []", stmt="a.append(1.0)", number=1000, repeat=5000)) * 1000
# 0.054 +/- 0.025 msec

# Python array with append()
np.mean(timeit.repeat(setup="import array; a = array.array('f')", stmt="a.append(1.0)", number=1000, repeat=5000)) * 1000
# 0.104 +/- 0.025 msec

# Numpy array with append()
np.mean(timeit.repeat(setup="import numpy as np; a = np.array([])", stmt="np.append(a, [1.0])", number=1000, repeat=5000)) * 1000
# 5.183 +/- 0.950 msec

# Python list using +=
np.mean(timeit.repeat(setup="a = []", stmt="a += [1.0]", number=1000, repeat=5000)) * 1000
# 0.062 +/- 0.021 msec

# Python array using += 
np.mean(timeit.repeat(setup="import array; a = array.array('f')", stmt="a += array.array('f', [1.0]) ", number=1000, repeat=5000)) * 1000
# 0.289 +/- 0.043 msec

# Python list using extend()
np.mean(timeit.repeat(setup="a = []", stmt="a.extend([1.0])", number=1000, repeat=5000)) * 1000
# 0.083 +/- 0.020 msec

# Python array using extend()
np.mean(timeit.repeat(setup="import array; a = array.array('f')", stmt="a.extend([1.0]) ", number=1000, repeat=5000)) * 1000
# 0.169 +/- 0.034
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.