Метод getitem был добавлен в Python как часть протокола последовательностей и отображений. С помощью этого магического метода стандартные коллекции (list, tuple, dict и др.) поддерживают доступ по индексу, ключу и срезу. В пользовательских классах этот метод позволяет объектам вести себя "как коллекции".
Без реализации getitem пользовательский класс не поддерживает индексирование и перебор по for. Реализация только для простых индексов неприменима, если хотим полноценную работу со срезами (slice), а игнорирование разновидностей индекса приведёт к ошибкам.
Реализовать getitem для поддержки и индексов, и объектов типа slice, разделяя их в обработке. Это позволяет использовать пользовательские объекты в стандартных конструкциях Python (например, для поддержки срезов your_obj[1:5]).
Пример кода:
class MyRange: def __init__(self, n): self.n = n def __getitem__(self, item): if isinstance(item, int): # Индивид. индекс if 0 <= item < self.n: return item * 2 raise IndexError('index out of range') elif isinstance(item, slice): # Срез return [self[i] for i in range(*item.indices(self.n))] else: raise TypeError('Invalid argument type: {}'.format(type(item))) mr = MyRange(10) print(mr[3]) # 6 print(mr[2:5]) # [4, 6, 8]
Ключевые особенности:
Обеспечивает ли реализация только getitem возможность присваивать значения по индексу?
Нет. Для поддержки присваивания (your_obj[i] = value) нужно реализовать setitem. getitem отвечает только за чтение.
Должен ли getitem обязательно отдавать список на срез, как list?
Нет. Главное — возвращать "последовательность" с учетом смысла класса (можно возвращать тот же тип или, к примеру, tuple). Главное, чтобы это было осмысленно в контексте задачи.
Почему иногда возникает ошибка TypeError: 'MyClass' object is not subscriptable?
Такое сообщение появляется, если вы пробуете выполнить my_obj[0], а класс не реализует getitem. Чтобы класс был subscriptable (поддерживал []), этот метод обязательный.
Реализовали getitem только для int, забыли про slice. Любая попытка my_obj[2:5] приводит к TypeError и сбою всего алгоритма обработки коллекций.
Плюсы:
Минусы:
getitem реализован с отдельной обработкой slice и int. Срезы и индексы работают, методы list(), map(), итерирования поддерживаются без дополнительных усилий.
Плюсы:
Минусы: