Python. Перегрузка операторов. Доступ к элементам по индексу

Перегрузка операторов. Доступ к элементам по индексу. Методы __getitem__() и __setitem__()


Содержание


Поиск на других ресурсах:

1. Перегрузка доступа по индексу [ ]. Метод __getitem__()

Чтобы обеспечить доступ по индексу в классе нужно реализовать методы __getitem__() и __setitem__(). Как правило, доступ по индексу требуется в классах реализующих наборы данных (массивы, списки и т.п.).

Метод __getitem__() вызывается, когда нужно считать данные по индексу. Приблизительный вид объявления метода в классе может быть следующим

class ClassName:
    # Составляющие класса
    ...

    def __getitem__(self, index):
        ...
        return self.objName[index]

здесь

  • ClassName – имя класса;
  • objName – итерированный объект, являющийся списком, кортежем и т.п.;
  • index – позиция (индекс) элемента в объекте objName.

Можно, конечно, реализовать метод __getitem__() и не для итерированного объекта, вкладывая в него определенный смысл.
После объявления метода __getitem__() можно обращаться к объекту класса привычным способом с помощью квадратных скобок [ ]

value = ClassName[index] # вызывается метод __getitem__()

здесь

  • value – некоторое значение;
  • index – позиция (индекс) итерированного объекта в классе ClassName.

 

2. Перегрузка доступа по индексу [ ]. Установка нового значения. Метод __setitem__()

Метод __setitem__() вызывается, когда нужно записать данные по индексу в объект класса. Этот объект класса является, как правило, списком, кортежем и т.п. Использование метода __setitem__() в классе может быть примерно таким

def ClassName:
    # Составляющие класса
    ...

    def __setitem__(self, index, newValue):
        self.objName[index] = newValue

здесь

  • ClassName – имя класса;
  • objName – имя итерированного объекта для которого устанавливается значение newValue в позиции index;
  • index – позиция (индекс) начинающаяся с 0;
  • newValue – новое значение, устанавливаемое в объекте objName.

После реализации метода __setitem__() в классе можно записывать данные в итерированный объект класса. Это выглядит приблизительно так

ClassName[index] = newValue

здесь

  • ClassName – имя класса содержащего итерированный объект;
  • index – позиция элемента в итерированном объекте;
  • newValue – новое значение.

 

3. Пример, демонстрирующий реализацию массива комплексных чисел и доступ по индексу к элементам массива

В примере объявляется класс ArrayComplex, содержащий следующие составляющие:

  • AC – имя массива комплексных чисел. Массив организован в виде списка. Каждый элемент массива представляет пару (re, im), являющуюся кортежем;
  • __init__() – конструктор. Создает пустой список AC;
  • метод Add() – обеспечивает добавление нового комплексного числа в массив. Число прилагается как кортеж вида (re, im), состоящий из действительной части комплексного числа (re) и мнимой части комплексного числа (im);
  • метод Count() – возвращает длину списка AC;
  • метод Print() – выводит список комплексных чисел в удобном виде;
  • метод __getitem__() – обеспечивает чтение по индексу элемента списка AC;
  • метод __setitem__() – обеспечивает запись в список чисел AC заданного значения в заданной позиции (индексе).

 

# Доступ по индексу. Перегрузка методов __getitem__(), __setitem__()
# Класс, реализующий массив комплексных чисел
class ArrayComplex:
# 1. Конструктор класса
    def __init__(self):
        # массив реализован в виде списка с именем AC
        self.AC = [] # создать пустой список
        return

    # 2. Метод, добавляющий комплексное число к списку.
    # Число добавляется в виде кортежа.
    # Здесь re - вещественная часть комплексного числа,
    # im - мнимая часть комплексного числа.
    def Add(self, re, im):
        self.AC = self.AC + [(re, im)]

    # 3. Метод, возвращающий количество элементов массива
    def Count(self):
        return len(self.AC)

    # 4. Метод, выводящий список комплексных чисел на экран
    def Print(self, msg):
        s = msg + " => [ "
        for c in self.AC:
            s = s + "(" + str(c[0]) + ", " + str(c[1]) + ") "
        s = s + "]"
        print(s)

    # 5. Методы, обеспечивающие доступ по индексу []
    # 5.1. Чтение элемента массива по индексу
    def __getitem__(self, index):
        return self.AC[index]

    # 5.2. Запись элемента по индексу,
    # значение value - это кортеж типа (re, im)
    def __setitem__(self, index, value):
        self.AC[index] = value

# ------- Использование класса -------
# 1. Создать объект класса ArrayComplex
AC = ArrayComplex()

# 2. Добавить несколько чисел
AC.Add(5, 8)
AC.Add(2, -4)
AC.Add(-3.5, -1.8)
AC.Add(2.8, 1)

# 3. Вывести содержимое объекта AC
AC.Print("AC")

# 4. Прочитать первый элемент массива
cm1 = AC[0] # викликається AC.__getitem__(0)
print("cm1 = ", cm1)

# Прочесть последний элемент массива
cm2 = AC[AC.Count()-1]
print("cm2 = ", cm2)

# 5. Записать новое значение в массив в позиции 1
AC[1] = (10, 20) # вызывается AC.__setitem__(1, (10, 20))

# 6. Повторно вывести массив
AC.Print("AC")

# 7. Получить объект среза и вывести срез
objSlice = AC[:AC.Count()]
print("Slice[:Count()-1] => ", objSlice)

# 8. Получить срез, содержащий первые 2 элемента
objSlice = AC[:3]
print("Slice[:2] => ", objSlice)

Результат

AC => [ (5, 8) (2, -4) (-3.5, -1.8) (2.8, 1) ]
('cm1 = ', (5, 8))
('cm2 = ', (2.8, 1))
AC => [ (5, 8) (10, 20) (-3.5, -1.8) (2.8, 1) ]
('Slice[:Count()-1] => ', [(5, 8), (10, 20), (-3.5, -1.8), (2.8, 1)])
('Slice[:2] => ', [(5, 8), (10, 20), (-3.5, -1.8)])

 

4. Пример, демонстрирующий доступ к объекту класса по индексу. Реализация классов Point и ListPoints

 

# Доступ по индексу
# Класс, описывающий точку на координатной плоскости,
# в классе используются внутренние поля x, y
class Point:
    # 1. Конструктор класса
    def __init__(self, x, y):
        self.x = x
        self.y = y
        return

    # 2. Методы доступа
    # 2.1. Установить новое значение x
    def SetXY(self, x, y):
        self.x = x
        self.y = y
        return

    # 2.2. Считать x, y
    def X(self) : return self.x
    def Y(self) : return self.y

    # Метод, выводящий точку на экран
    def Print(self, msg):
        s = msg + " = (" + str(self.x) + "; " + str(self.y) + ")";
        print(s)

# Класс, описывающий массив точек, имеющий имя AP
class ListPoints:
    # конструктор
    def __init__(self):
        self.AP = [] # Создать пустой список

    # Метод, додающий точку в конец списка
    def Add(self, pt):
        self.AP = self.AP + [pt]

    # Метод возвращающий список точек
    def GetList(self): return self.AP

    # Метод, который выводит список точек
    def Print(self, msg):
        s = msg + " = [" # сформировать строку вывода
        for p in self.AP:
            s = s + "(" + str(p.X()) + "; " + str(p.Y()) + ") "
            print(s + ']\n')

    # Методы, реализующие доступ по индексу
    # Получить точку по индексу index
    def __getitem__(self, index):
        return self.AP[index]

    # Записать новую точку в позиции index
    def __setitem__(self, index, value):
        self.AP[index] = value

# ------- Использование классов Point и ListPoints -------
# 1. Создать некоторую точку
p1 = Point(2, 8.3)
p1.Print("p1")

# 2. Создать массив точек типа Point
# 2.1. Создать пустой массив
ArrayPoints = ListPoints()

# 2.2. Добавить к массиву 3 точки
ArrayPoints.Add(p1) # Добавить точку p1
ArrayPoints.Add(Point(3, 7.1)) # добавить точку (3, 7.1)
ArrayPoints.Add(Point(2, 1.6))

# 2.3. Вывести массив точек
ArrayPoints.Print("ArrayPoints")

# 3. Считать точку с индексом 0
pt = ArrayPoints[0] # здесь вызывается метод __getitem__()
pt.Print("ArrayPoints[0]")

# 4. Записать новое значение в точку с индексом 1
ArrayPoints[1] = Point(1.5, 2.3) # вызывается метод __setitem__()

# 5. Вывести массив заново
ArrayPoints.Print("ArrayPoints")

Результат

p1 = (2; 8.3)
ArrayPoints = [(2; 8.3) (3; 7.1) (2; 1.6) ]

ArrayPoints[0] = (2; 8.3)
ArrayPoints = [(2; 8.3) (1.5; 2.3) (2; 1.6) ]

 


Связанные темы