Последовательности данных в языке программирования Python

Раздел: Типы данных -> Последовательности

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

Основные принципы работы с последовательностями

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

Пример общих операций, доступных для любой последовательности:


seq = [10, 20, 30, 40, 50]
print(len(seq))        # 5
print(seq[2])          # 30
print(seq[1:4])        # [20, 30, 40]
print(30 in seq)       # True
print(10 not in seq)   # False
print(seq + [60, 70])  # [10, 20, 30, 40, 50, 60, 70]
print(seq * 2)         # [10, 20, 30, 40, 50, 10, 20, 30, 40, 50]

типам последовательностям python (типы последовательностей в python)

Все эти операции работают и с кортежами, строками, range, bytes и bytearray.

Типичные ошибки: попытка обратиться к несуществующему индексу приводит к IndexError. Использование дробного индекса (TypeError: list indices must be integers or slices, not float). При попытке изменения кортежа возникает TypeError: 'tuple' object does not support item assignment.

Как создать и модифицировать изменяемую последовательность?

Тип list предназначен для хранения упорядоченного набора элементов, которые могут быть изменены. Список создается с помощью квадратных скобок или функции list().


# Создание списка
fruits = ['apple', 'banana', 'cherry']
numbers = list(range(5))
mixed = [1, 'hello', 3.14, True]
print(fruits)  # ['apple', 'banana', 'cherry']
# Изменение элемента
fruits[1] = 'blueberry'
print(fruits)  # ['apple', 'blueberry', 'cherry']
# Добавление элемента
fruits.append('date')
print(fruits)  # ['apple', 'blueberry', 'cherry', 'date']
# Удаление по значению
fruits.remove('apple')
print(fruits)  # ['blueberry', 'cherry', 'date']

Частая проблема: при удалении элемента по значению remove() удаляет только первое вхождение. Если элемент отсутствует, возникает ValueError: list.remove(x): x not in list. Перед удалением следует проверять наличие элемента оператором in.

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

Как создать неизменяемую последовательность?

Кортеж (tuple) похож на список, но его элементы нельзя изменить после создания. Кортежи создаются с помощью круглых скобок или функции tuple(). Они часто применяются для фиксированных наборов данных, таких как координаты, дни недели, константы.


# Создание кортежа
point = (3, 4)
weekdays = ('Monday', 'Tuesday', 'Wednesday')
single = (42,)  # обязательная запятая для одного элемента
print(point)  # (3, 4)
# Доступ по индексу
print(weekdays[0])  # 'Monday'
# Распаковка
x, y = point
print(x, y)  # 3 4

Типичная ошибка: попытка изменить элемент кортежа TypeError: 'tuple' object does not support item assignment. Если кортеж содержит изменяемые объекты (например, список), внутренние изменения возможны, но это считается плохой практикой.

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

Как сгенерировать последовательность чисел без хранения всех значений?

Тип range представляет неизменяемую последовательность чисел, вычисляемых по мере необходимости. Он экономит память при больших диапазонах. Используется в циклах for и для создания списков.


# Создание range
r1 = range(10)          # 0..9
r2 = range(2, 10, 2)   # 2, 4, 6, 8
print(list(r1))  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(len(r2))   # 4
print(5 in r1)   # True
# Доступ по индексу
print(r2[1])     # 4

Важно: range поддерживает только целые числа. При попытке использовать шаг 0 будет ValueError: range() arg 3 must not be zero. Также нельзя изменить range после создания.

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

Как работать с текстовыми данными как с последовательностью?

Строка (str) является неизменяемой последовательностью символов Unicode. Поддерживает все операции последовательности, а также множество методов для обработки текста.


text = 'Python programming'
print(len(text))         # 18
print(text[0])           # P
print(text[-1])          # g
print(text[7:12])        # 'progr'
print('Python' in text)  # True
# Конкатенация
new_text = text + ' language'
print(new_text)          # 'Python programming language'
# Повторение
print('Hi! ' * 3)        # 'Hi! Hi! Hi! '

Ошибки: строки неизменяемы, поэтому присвоение по индексу (text[0] = 'p') вызывает TypeError: 'str' object does not support item assignment. Для замены символов нужно создавать новую строку методами вроде replace() или срезов.

Строки используются для представления и обработки текстовой информации. Методы split(), join(), strip() значительно упрощают работу.

Как работать с двоичными данными как с последовательностью?

Тип bytes представляет неизменяемую последовательность байтов (целых чисел от 0 до 255). bytearray - изменяемый аналог. Они используются для работы с двоичными файлами, сетевыми протоколами и кодировками.


# Создание bytes
b = b'hello'           # байтовый литерал
# b = bytes([104, 101, 108, 108, 111])
print(b[0])            # 104 (код 'h')
# Создание bytearray
ba = bytearray([1, 2, 3, 255])
ba[1] = 10
print(ba)              # bytearray(b'\x01\n\x03\xff')
# Срез
print(ba[0:2])         # bytearray(b'\x01\n')

Проблемы: при попытке присвоить значение вне диапазона 0-255 в bytearray возникает ValueError: byte must be in range(0, 256). Строки и байты не смешиваются автоматически; для перевода нужны методы encode()/decode().

Типы bytes и bytearray используются при чтении/записи бинарных файлов, работе с шифрованием, сокетами, протоколами низкого уровня.

Расширенные примеры работы с последовательностями

Пример 1. Срезы с шагом и отрицательные индексы

Пример

data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Шаг 2
print(data[::2])          # [0, 2, 4, 6, 8]
# Обратный порядок
print(data[::-1])         # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
# Срез с конца с шагом -2
print(data[-1::-2])       # [9, 7, 5, 3, 1]
[0, 2, 4, 6, 8]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
[9, 7, 5, 3, 1]

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

Пример 2. Копирование списков: поверхностное и глубокое

Пример

import copy
original = [[1, 2], [3, 4]]
# Поверхностная копия
shallow = original.copy()
shallow[0][0] = 99
print(original)  # [[99, 2], [3, 4]] - изменено!
# Глубокая копия
deep = copy.deepcopy(original)
deep[0][0] = 0
print(original)  # [[99, 2], [3, 4]] - не изменено
[[99, 2], [3, 4]]
[[99, 2], [3, 4]]

Для списков и bytearray следует различать копирование ссылок и содержимого.

Пример 3. Преобразование строки в bytes и обратно, модификация bytearray

Пример

# Строка в байты
s = 'Привет'
b = s.encode('utf-8')
print(b)  # b'\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82'
# Байты в строку
s2 = b.decode('utf-8')
print(s2)  # Привет
# Создание bytearray и изменение
ba = bytearray(b'abcdef')
ba[2:5] = b'XYZ'  # замена среза
print(ba)          # bytearray(b'abXYZf')
b'\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82'
Привет
bytearray(b'abXYZf')

Метод encode()/decode() обязателен при переходе между str и bytes. Bytearray поддерживает изменение срезов.

Пример 4. Memoryview для эффективного доступа к байтовому буферу

Пример

ba = bytearray(b'A' * 10)
mv = memoryview(ba)
# Чтение через memoryview
print(mv[0])      # 65 (код 'A')
# Создание среза без копирования
mv_slice = mv[2:5]
mv_slice[0] = 66  # изменяет оригинальный ba
print(ba)         # bytearray(b'AABAAAAAAA')
65
bytearray(b'AABAAAAAAA')

Memoryview позволяет работать с буфером байтового массива, не создавая копии подстроки.

Пример 5. Генерация списка с условием (list comprehension)

Пример

# Список квадратов чётных чисел от 0 до 9
squares = [x**2 for x in range(10) if x % 2 == 0]
print(squares)  # [0, 4, 16, 36, 64]
# Эквивалентный цикл
squares2 = []
for x in range(10):
    if x % 2 == 0:
        squares2.append(x**2)
print(squares2) # [0, 4, 16, 36, 64]
[0, 4, 16, 36, 64]
[0, 4, 16, 36, 64]

Генераторы списков (list comprehensions) предоставляют лаконичный способ создания последовательностей на основе существующих.

Пример 6. Упаковка и распаковка кортежей

Пример

# Упаковка
t = 1, 2, 3   # без скобок - тоже кортеж
print(t)      # (1, 2, 3)
# Распаковка с *
first, *middle, last = (10, 20, 30, 40, 50)
print(first, middle, last)  # 10 [20, 30, 40] 50
(1, 2, 3)
10 [20, 30, 40] 50

Распаковка с * (звездочка) позволяет захватывать оставшиеся элементы в список.

Пример 7. Сравнение производительности list и tuple

Пример

import timeit
# Время создания
list_time = timeit.timeit('list(range(1000))', number=10000)
tuple_time = timeit.timeit('tuple(range(1000))', number=10000)
print(f'list: {list_time:.4f}, tuple: {tuple_time:.4f}')
# Время доступа по индексу
access_list = timeit.timeit('l[500]', setup='l = list(range(1000))', number=1000000)
access_tuple = timeit.timeit('t[500]', setup='t = tuple(range(1000))', number=1000000)
print(f'list access: {access_list:.4f}, tuple access: {access_tuple:.4f}')
list: 0.2345, tuple: 0.1876
list access: 0.0456, tuple access: 0.0443

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

Пример 8. Вложенные последовательности и их обработка

Пример

# Список кортежей (например, координаты)
points = [(1, 2), (3, 4), (5, 6)]
# Извлечение x и y с помощью распаковки
for x, y in points:
    print(f'x={x}, y={y}')
# Кортеж списков
data = ([1, 2], [3, 4])
# Изменение вложенного списка
data[0].append(5)
print(data)  # ([1, 2, 5], [3, 4])
x=1, y=2
x=3, y=4
x=5, y=6
([1, 2, 5], [3, 4])

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

Типы последовательностей в Python - comments

En
типам последовательностям python (python)