← Назад к вопросам

Какие методы должна реализовывать последовательность в Python?

2.0 Middle🔥 41 комментариев
#Git и VCS

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Методы последовательности в Python

В Python последовательность — это упорядоченный набор элементов с доступом по индексу. Существует протокол (ABC — Abstract Base Class), определяющий, какие методы должны реализовать пользовательские последовательности.

Обязательные методы (Minimal Protocol)

Для создания базовой последовательности необходимо реализовать как минимум два метода:

from collections.abc import Sequence

class MySequence(Sequence):
    def __init__(self, data):
        self._data = data
    
    def __getitem__(self, index):
        """Получение элемента по индексу (обязательно)"""
        if isinstance(index, slice):
            return MySequence(self._data[index])
        return self._data[index]
    
    def __len__(self):
        """Получение длины последовательности (обязательно)"""
        return len(self._data)

# Использование
seq = MySequence([1, 2, 3, 4, 5])
print(seq[2])          # 3
print(len(seq))        # 5
print(seq[1:3])        # MySequence([2, 3])

Эти два метода достаточно для получения остального функционала автоматически!

Автоматически полученные методы

Когда вы наследуетесь от Sequence, получаете эти методы бесплатно:

seq = MySequence([1, 2, 3, 1, 4])

# Проверка содержимого
print(2 in seq)                    # True (через __getitem__)
print(seq.index(1))                # 0 (первый индекс элемента)
print(seq.count(1))                # 2 (количество элементов)

# Итерация
for item in seq:                   # Работает через __getitem__
    print(item)

# Реверс
print(list(reversed(seq)))         # [4, 1, 3, 2, 1]

# Распаковка
a, b, c, *rest = seq               # Работает через __iter__

Основные методы, наследуемые от Sequence

seq = MySequence([1, 2, 3, 4, 5])

# 1. __contains__ (in оператор)
print(3 in seq)                    # True
print(10 in seq)                   # False

# 2. __iter__ (итерация)
iterator = iter(seq)
print(next(iterator))              # 1
print(next(iterator))              # 2

# 3. __reversed__ (обратный порядок)
for item in reversed(seq):
    print(item)                    # 5, 4, 3, 2, 1

# 4. index(value, start=0, stop=None) - индекс элемента
print(seq.index(3))                # 2

# 5. count(value) - количество вхождений
seq2 = MySequence([1, 2, 1, 3, 1])
print(seq2.count(1))               # 3

Полная иерархия методов

from collections.abc import Sequence, MutableSequence

# Читаемая последовательность (неизменяемая)
class ImmutableSeq(Sequence):
    def __init__(self, data):
        self._data = tuple(data)
    
    def __getitem__(self, index):
        return self._data[index]
    
    def __len__(self):
        return len(self._data)

# Изменяемая последовательность
class MutableSeq(MutableSequence):
    def __init__(self, data):
        self._data = list(data)
    
    def __getitem__(self, index):
        return self._data[index]
    
    def __setitem__(self, index, value):
        """Установка значения (обязательно для MutableSequence)"""
        self._data[index] = value
    
    def __delitem__(self, index):
        """Удаление элемента (обязательно для MutableSequence)"""
        del self._data[index]
    
    def __len__(self):
        return len(self._data)
    
    def insert(self, index, value):
        """Вставка элемента (обязательно для MutableSequence)"""
        self._data.insert(index, value)

# Использование
seq = MutableSeq([1, 2, 3])
seq[1] = 20                        # Изменение
seq.insert(2, 100)                 # Вставка
seq.append(4)                      # Автоматический append!
print(seq._data)                   # [1, 20, 100, 3, 4]

Методы, автоматичные для MutableSequence

При реализации трёх методов (__setitem__, __delitem__, insert) вы получаете:

seq = MutableSeq([1, 2, 3, 4, 5])

# Наследуемые методы:
seq.append(6)                      # Добавить в конец
seq.extend([7, 8])                 # Расширить
seq.insert(0, 0)                   # Вставить
seq.remove(3)                      # Удалить первое вхождение
seq.pop()                          # Удалить последний
seq.pop(0)                         # Удалить по индексу
seq.clear()                        # Очистить
seq.reverse()                      # Развернуть на месте
seq += [10, 11]                    # +=
seq *= 2                           # *=

Сравнение с встроенными типами

# list - MutableSequence
print(isinstance([1, 2, 3], MutableSequence))  # True

# tuple - Sequence
print(isinstance((1, 2, 3), Sequence))         # True
print(isinstance((1, 2, 3), MutableSequence))  # False

# str - Sequence
print(isinstance("hello", Sequence))           # True

Лучшие практики

# ✅ Хорошо - используй ABC для типизации
def process_sequence(seq: Sequence) -> None:
    for item in seq:
        print(item)

# ✅ Правильное наследование
class CustomList(MutableSequence):
    def __init__(self, data=None):
        self._data = list(data or [])
    
    def __getitem__(self, index):
        if isinstance(index, slice):
            return CustomList(self._data[index])
        return self._data[index]
    
    def __setitem__(self, index, value):
        self._data[index] = value
    
    def __delitem__(self, index):
        del self._data[index]
    
    def __len__(self):
        return len(self._data)
    
    def insert(self, index, value):
        self._data.insert(index, value)

# ❌ Плохо - полное переопределение методов
class BadList:
    def __getitem__(self, index):
        # ...
    def __setitem__(self, index, value):
        # ...
    # Пришлось бы переопределить все методы вручную!

Использование правильных ABC экономит время и обеспечивает совместимость с остальным кодом Python.