Python. Перегрузка сокращенных операторов присваивания

Перегрузка сокращенных операторов присваивания

Перед изучением данной темы рекомендуется ознакомиться со следующей темой:


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

Содержание


1. Особенности перегрузки сокращенных операторов присваивания +=, -=, *=, /=, %=, //=

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

  • __iadd__() – перегружает сокращенный оператор присваивания +=;
  • __isub__() – перегружает оператор -=;
  • __imul__() – перегружает оператор *=;
  • __idiv__() – перегружает оператор /=;
  • __ifloordiv__() – перегружает оператор //=;
  • __imod__() – перегружает оператор %=.

Реализация каждого из этих методов в классе требует получения двух параметров:

  • параметра типа self – текущий объект класса (this);
  • параметра, имеющего тип данного класса. Этот параметр является объектом, используемым в правой части сокращенного оператора присваивания.

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

obj1 op obj2

здесь

  • obj1, obj2 – объекты класса;
  • op – одна из операций +=, -=, *=, /=, //=, %=.

Например, для перегрузки оператора += в классе A может быть примерно следующий код

class A:

    # ...

    # перегрузка оператора +=
    def __iadd__(self, obj):
        # Действия, которые нужно выполнить
        # ...

# Вызов перегруженного оператора +=
obj1 = A()
obj2 = A()
obj1 += obj2

 

2. Перегрузка сокращенных операторов присваивания. Класс Fraction (дробь)

В примере объявляется класс Fraction (дробь). В классе объявляются две внутренние переменные:

  • num (self.num) – числитель дроби;
  • denom (self.denom) – знаменатель дроби.

В классе Fraction демонстрируется перегрузка методов +=, -=, *=, /=, %=, //=.

# Перегрузка операторов +=, -=, *=, /=, %=, //=

# Класс, описывающий дробь, заданную числителем и знаменателем:
# - num - числитель;
# - denom - знаменатель.
class Fraction:

    # Конструктор класса, num - числитель, denom - знаменатель
    def __init__(self, num, denom):
        self.num = num
        self.denom = denom

        # Корректировка num, denom
        if self.num == 0: self.num = 1
        if self.denom == 0: self.denom = 1

        self.Normal()
        return

    #-------------- Методы перегрузки операторов --------------
    # Перегрузка оператора +=
    # Добавление к данной дроби другой дроби - метод __iadd__()
    def __iadd__(self, frac):
        obj = Fraction((self.num*frac.denom+self.denom*frac.num), self.denom*frac.denom)
        return obj

    # Перегрузка оператора -=
    # Вычитание от данной дроби другой дроби - метод __isub__()
    def __isub__(self, frac):
        # вычитание дробей
        obj = Fraction((self.num*frac.denom-self.denom*frac.num), self.denom*frac.denom)
        return obj

    # Перегрузка оператора *= - метод __imul__()
    def __imul__(self, frac):
        obj = Fraction(self.num*frac.num, self.denom*frac.denom)
        return obj

    # Перегрузка оператора /= - метод __idiv__()
    def __idiv__(self, frac):
        obj = Fraction(self.num*frac.denom, self.denom*frac.num)
        return obj

    # Перегрузка оператора //= - метод __ifloordiv__()
    def __ifloordiv__(self, frac):
        # Метод возвращает результат деления дробей так же как и метод idiv()
        return Fraction(self.num*frac.denom, self.denom*frac.num)

    # Перегрузка оператора %= - метод __imod__()
    def __imod__(self, frac):
        # Метод возвращает инвертированную дробь: 5/6 => 6/5
        return Fraction(self.denom, self.num)

    # ---------------------------------------------------------
    # Метод, выводящий значение внутренних координат x, y
    def Print(self, msg):
        print(msg, " => ", self.num, " / ", self.denom)
        return

    # Метод, нормализующий дробь 8/12 => 2/3
    def Normal(self):
        t = abs(self.num)
        i = 1
        num = i
        while i <= t:
            if ((self.num%i) == 0) and ((self.denom%i) == 0):
                num = i
            i = i+1

        self.num = self.num / num
        self.denom = self.denom / num

        # (-num)/(-denom) => num/denom
        if (self.num<0) and (self.denom<0):
            self.num = -self.num
            self.denom = -self.denom

        return

# Тестирование
f1 = Fraction(1, 2) # конструктор
f1.Print("f1")

f2 = Fraction(2, 3) # конструктор
f2.Print("f2")

f1 += f2 # метод __iadd__()
f1.Print("f1+=f2")

f1 -= f2 # метод __isub__()
f1.Print("f1-=f2")

f1 *= f2 # метод __imul__()
f1.Print("f1*=f2")

f1 /= f2 # метод __idiv__()
f1.Print("f1/=f2")

f1 //=f2 # метод __ifloordiv__()
f1.Print("f1//f2")

f1 %= f1 # метод __imod__()
f1.Print("f1%=f1")

Результат

f1 => 1 / 2)
f2 => 2 / 3)
f1+=f2 => 7 / 6
f1-=f2 => 1 / 2)
f1*=f2 => 1 / 3)
f1/=f2 => 1 / 2)
f1//f2 => 3 / 4)
f1%=f1 => 4 / 3)

 

3. Пример перегрузки сокращенных операторов присвоения. Классы Point и ArrayPoint. Оперирование массивом точек

В этом примере объявляются классы Point и ArrayPoint. Класс Point описывает точку на координатной плоскости. Класс ArrayPoint описывает массив точек типа Point. Массив реализован в виде списка.

В классе ArrayPoint перегружается сокращенный оператор присваивания += реализующий конкатенацию массивов типа ArrayPoint.

# Перегрузка оператора += для добавления списков объектов

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

    # Методы, возвращающие координаты точки
    def GetX(self): return self.x
    def GetY(self): return self.y

    # Метод, который выводит координаты точки
    def Print(self, msg):
        print(msg, "=> (", self.x, "; ", self.y, ")")

# Класс, реализующий массив точек:
# - AP - массив точек.
# В классе перегружается оператор +=, который
# делает конкатенацию двух массивов точек.
class ArrayPoint:
    # Конструктор 2 - создает пустой массив
    def __init__(self):
        self.AP = [] # массив в виде списка

    # Метод, добавляющий элемент к массиву
    def Add(self, pt):
        self.AP = self.AP + [pt]

    # Метод, возвращающий массив self.AP
    def Get(self):
        return self.AP

    # Метод, который выводит массив точек
    def Print(self, msg):
        print(msg)
        for pt in self.AP:
            pt.Print("")

    # Метод, который перегружает оператор +=,
    # метод добавляет к массиву self.AP точек другой массив
    def __iadd__(self, AP2):
        # 1. Объединить списки двух объектов
        lst = self.AP + AP2.Get()

        # 2. Создать результирующий объект
        obj = ArrayPoint()

        # 3. Прибавить к объекту obj элементы списка
        for t in lst:
            obj.Add(t)

        # Вернуть результирующий объект
        return obj

# Тест

# 1. Создать массив точек AP1
AP1 = ArrayPoint()
AP1.Add(Point(2, 3))
AP1.Add(Point(4, 7))
AP1.Add(Point(8, 3))
AP1.Print("AP1")

# 2. Создать массив точек AP2
AP2 = ArrayPoint()
AP2.Add(Point(-2, 4))
AP2.Add(Point(7, 6))
AP2.Print("AP2")

# 3. Добавить массивы
AP1 += AP2
AP1.Print("AP1 += AP2")

Результат

AP1
('', '=> (', 2, '; ', 3, ')')
('', '=> (', 4, '; ', 7, ')')
('', '=> (', 8, '; ', 3, ')')
AP2
('', '=> (', -2, '; ', 4, ')')
('', '=> (', 7, '; ', 6, ')')
AP1 += AP2
('', '=> (', 2, '; ', 3, ')')
('', '=> (', 4, '; ', 7, ')')
('', '=> (', 8, '; ', 3, ')')
('', '=> (', -2, '; ', 4, ')')
('', '=> (', 7, '; ', 6, ')')

 


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