Массивы Python
Узнайте, как создавать и использовать массивы Python с модулем array: типкоды, индексирование, срезы, изменение элементов и выбор между array и списком.
В этой главе рассматривается встроенный модуль Python array, предоставляющий компактную последовательность с ограничением типа для хранения однородных числовых данных. Вы узнаете, что такое типкоды, как создавать и индексировать массивы, как изменять их с помощью полного набора доступных методов и — что особенно важно — когда array является правильным выбором вместо обычного Python-списка.
Что такое модуль array?
Модуль Python array предоставляет тип последовательности, хранящий элементы единственного совместимого с C числового типа. В отличие от списка, который может содержать любой набор объектов, каждый слот в array хранит ровно одно и то же примитивное значение (целое число, число с плавающей точкой и т. д.). Это ограничение делает массивы более эффективными с точки зрения использования памяти, чем списки, при хранении больших коллекций чисел.
Ключевые особенности:
- Определён в стандартной библиотеке — установка не требуется.
- Все элементы должны иметь одинаковый типкод (один символ, идентифицирующий тип C).
- Поддерживает стандартные операции с последовательностями: индексирование, срезы, итерацию,
len()и проверку членства с помощьюin. - Полезен, когда нужно компактное хранение данных без обращения к сторонним библиотекам вроде NumPy.
Если вы уже знакомы со списками Python, думайте об array как о списке, который жертвует гибкостью ради экономии памяти.
Типкоды
Каждый array создаётся с типкодом — строкой из одного символа, указывающей Python, какой тип C использовать для каждого элемента и сколько байт занимает каждый слот.
| Типкод | Тип C | Минимум байт | Типичное применение |
|---|---|---|---|
'b' | signed char | 1 | Малые целые от −128 до 127 |
'B' | unsigned char | 1 | Малые неотрицательные целые 0–255 |
'h' | signed short | 2 | Средние целые числа |
'H' | unsigned short | 2 | Средние неотрицательные целые |
'i' | signed int | 2 | Целые числа общего назначения (обычно 4 байта) |
'I' | unsigned int | 2 | Неотрицательные целые |
'l' | signed long | 4 | Большие целые числа |
'L' | unsigned long | 4 | Большие неотрицательные целые |
'q' | signed long long | 8 | Очень большие целые числа |
'Q' | unsigned long long | 8 | Очень большие неотрицательные целые |
'f' | float | 4 | Числа с плавающей точкой одинарной точности |
'd' | double | 8 | Числа с плавающей точкой двойной точности |
Фактический размер в байтах может варьироваться в зависимости от платформы. Используйте array.itemsize, чтобы узнать его во время выполнения.
Примечание о
'u'(символ Unicode): Этот типкод был устаревшим начиная с Python 3.3 и удалён в Python 3.13. Не используйте его в новом коде — вместо него применяйтеstrилиbytes.
Создание массивов
Импортируйте модуль и вызовите array.array(typecode, initializer), где initializer — любой итерируемый объект из значений, совместимых с выбранным типкодом.
import array as arr
# Array of signed integers
int_array = arr.array('i', [1, 2, 3, 4, 5])
print(int_array) # array('i', [1, 2, 3, 4, 5])
# Array of double-precision floats
float_array = arr.array('d', [1.1, 2.2, 3.3])
print(float_array) # array('d', [1.1, 2.2, 3.3])
# Inspect the typecode and bytes-per-element
print(int_array.typecode) # i
print(int_array.itemsize) # 4 (platform-dependent)Можно также создать пустой массив и заполнить его позже:
import array as arr
empty = arr.array('i') # empty integer array
empty.append(10)
empty.append(20)
print(empty) # array('i', [10, 20])Обращение к элементам массива
Индексирование массива работает точно так же, как индексирование списка: с нуля слева, а отрицательные индексы отсчитываются справа.
Обращение к индексу за пределами допустимого диапазона вызывает IndexError, точно так же, как и для списков.
Срезы массивов
Срез возвращает новый array с тем же типкодом, содержащий выбранные элементы. Синтаксис: a[start:stop:step] — такой же, как для списков и строк.
Итерация по массиву
Можно перебирать элементы массива с помощью цикла for или проверять вхождение с помощью in:
import array as arr
a = arr.array('i', [10, 20, 30, 40, 50])
for item in a:
print(item, end=' ')
# Output: 10 20 30 40 50
print()
print(30 in a) # True
print(99 in a) # False
print(len(a)) # 5Изменение массивов
Массивы являются изменяемыми — после создания можно изменять, добавлять и удалять элементы.
Изменение элемента
Присвойте новое значение непосредственно по индексу:
Добавление элементов
Используйте append() для добавления одного элемента в конец или extend() для добавления нескольких элементов из любого итерируемого объекта:
Используйте insert(index, value) для вставки элемента в заданную позицию:
import array as arr
a = arr.array('i', [1, 2, 3, 4, 5])
a.insert(2, 10) # insert 10 before index 2
print(a) # array('i', [1, 2, 10, 3, 4, 5])Удаление элементов
remove(value) удаляет первое вхождение указанного значения и вызывает ValueError, если оно не найдено:
pop(index) удаляет и возвращает элемент по index (по умолчанию — последний элемент):
import array as arr
a = arr.array('i', [1, 2, 3, 4, 5])
last = a.pop() # removes and returns 5
print(last) # 5
print(a) # array('i', [1, 2, 3, 4])
second = a.pop(1) # removes and returns element at index 1
print(second) # 2
print(a) # array('i', [1, 3, 4])Поиск и подсчёт
index(value) возвращает индекс первого вхождения value (вызывает ValueError, если значение отсутствует):
import array as arr
a = arr.array('i', [10, 20, 30, 20, 40])
print(a.index(20)) # 1 — first occurrence
print(a.index(30)) # 2count(value) возвращает количество вхождений value:
import array as arr
a = arr.array('i', [1, 2, 2, 3, 2, 4])
print(a.count(2)) # 3
print(a.count(9)) # 0Разворот массива
reverse() разворачивает массив на месте:
import array as arr
a = arr.array('i', [1, 2, 3, 4, 5])
a.reverse()
print(a) # array('i', [5, 4, 3, 2, 1])Преобразование между массивами и списками
tolist() преобразует массив в стандартный Python-список. Чтобы выполнить обратное преобразование, передайте список в array.array():
import array as arr
a = arr.array('i', [1, 2, 3, 4, 5])
# array → list
my_list = a.tolist()
print(my_list) # [1, 2, 3, 4, 5]
print(type(my_list)) # <class 'list'>
# list → array
back = arr.array('i', my_list)
print(back) # array('i', [1, 2, 3, 4, 5])Изменение типа элементов
Атрибут typecode доступен только для чтения. Чтобы сохранить те же значения с другим типом, создайте новый массив, используя исходный в качестве инициализатора:
Эффективность памяти: массивы vs. списки
Основная практическая причина использовать модуль array вместо списка — это память. Список хранит ссылки на Python-объекты; array хранит необработанные значения C напрямую.
import array as arr
import sys
n = 1000
my_list = list(range(n))
my_array = arr.array('i', range(n))
print('List size:', sys.getsizeof(my_list), 'bytes')
print('Array size:', sys.getsizeof(my_array), 'bytes')
# Example output (64-bit platform):
# List size: 8056 bytes
# Array size: 4096 bytesДля больших наборов данных (сотни тысяч целых чисел) экономия становится весьма значительной. Если вам нужны ещё большие возможности — векторизованные вычисления, многомерные массивы — рассмотрите NumPy.
Когда использовать array, а когда списки
Используйте модуль array, когда:
- Вы храните большое количество однородных числовых значений (показания датчиков, данные пикселей, сетевые буферы и т. д.).
- Использование памяти является проблемой и вы не можете использовать стороннюю библиотеку.
- Вы читаете из двоичных файлов или сетевых сокетов или записываете в них (методы
tofile()/fromfile()делают это простым).
Используйте списки Python, когда:
- Нужно хранить смешанные типы или произвольные объекты.
- Коллекция небольшая и память не является проблемой.
- Вам нужны расширенные методы списков, например
sort()с функцией-ключом.
Используйте NumPy, когда:
- Нужны математические операции над целыми массивами (векторизованная арифметика, матричная алгебра, статистика).
- Вы работаете с многомерными данными.
Справочник методов
| Метод | Описание |
|---|---|
append(x) | Добавляет x в конец массива |
extend(iterable) | Добавляет все элементы из iterable в конец |
insert(i, x) | Вставляет x перед индексом i |
remove(x) | Удаляет первое вхождение x |
pop([i]) | Удаляет и возвращает элемент по индексу i (по умолчанию: последний) |
index(x) | Возвращает индекс первого вхождения x |
count(x) | Возвращает количество вхождений x |
reverse() | Разворачивает массив на месте |
tolist() | Преобразует массив в Python-список |
tofile(f) | Записывает все элементы в открытый файловый объект f в виде машинных значений |
fromfile(f, n) | Читает n элементов из файлового объекта f и добавляет их в массив |