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, ')')

 


Споріднені теми