Python. Перевантаження бінарних арифметичних операторів у класах

Перевантаження бінарних арифметичних операторів у класах


Пошук на інших ресурсах:

Зміст


1. Загальні відомості про перевантаження бінарних арифметичних операторів +, , *, /, //, %

Бінарні арифметичні оператори в класах отримують 2 операнди. Загальна форма виклику бінарного арифметичного оператора має вигляд:

res = a op b

тут

  • a, b – операнди, над яким здійснюється операція;
  • op – одна з операцій +, –, *, /, //, %;
  • res – результуючий об’єкт.

Для перевантаження відповідного бінарного оператора у класі потрібно реалізувати відповідний метод.

Нижче наведено перелік загальних методів для перевантаження бінарних операторів +, –, *, /, //, %, які оперують об’єктами:

  • метод __add__() – перевантаження бінарного оператора + (додавання). Метод викликається у виразі на кшталт a+b;
  • метод __sub__() – перевантаження бінарного оператора – (віднімання). Метод викликається при відніманні об’єктів a–b;
  • метод __mul__() – перевантаження бінарного оператора * (множення). Метод викликається при множенні двох операндів a*b;
  • метод __div__() – перевантаження бінарного оператора / (ділення). Викликається у виразах на зразок a/b;
  • метод __mod__() – перевантаження бінарного оператора % (остача від ділення). Викликається у виразі a%b;
  • метод __floordiv__() – перевантаження бінарного оператора // (ділення з округленням вниз). Викликається у виразі a // b.

   

2. Приклад перевантаження операторів +, –. Клас Point

У прикладі оголошується клас Point, який реалізує точку на координатній площині. У класі перевантажуються оператори + (додавання) та – (віднімання). Для цього у класі оголошуються методи __add__() та __sub__().

# Перевантаження бінарного оператора +

# Клас, що описує точку на координатній площині
class Point:

    # Конструктор класу
    def __init__(self, x, y):
        self.x = x
        self.y = y
        return

    # Методи доступу до полів self.x, self.y
    def GetX(): return self.x
    def GetY(): return self.y
    def SetXY(self, x, y):
        self.x = x
        self.y = y
        return

    #-------------- Методи перевантаження операторів --------------
    # Перевантаження бінарного оператора + (додавання об'єктів) - метод __add__()
    def __add__(self, pt):
        obj = Point(self.x + pt.x, self.y + pt.y)
        return obj

    # Перевантаження бінарного оператора віднімання - метод __sub__()
    def __sub__(self, pt):
        # віднімання координат
        obj = Point(self.x - pt.x, self.y - pt.y)
        return obj

    # ---------------------------------------------------------
    # Метод, що виводить значення внутрішніх координат x, y
    def Print(self, msg):
        print(msg, " => x = ", self.x, "; y = ", self.y)
        return

# Тестування
pt1 = Point(1,3)
pt1.Print("pt1")

pt2 = Point(2,6)
pt2.Print("pt2")

pt3 = pt1 + pt2
pt3.Print("pt1 + pt2")

(pt1-pt2).Print("pt1 - pt2")

Результат

pt1 => x = 1, y = 3
pt2 => x = 2, y = 6
pt1 + pt2 => x = 3, y = 9
pt1 - pt2 => x = -1, y = -3

   

3. Приклад перевантаження операторів +, , *, /, //, % для класу Fraction (Дріб)

У прикладі оголошується клас Fraction (Дріб) в якому перевантажуються стандартні бінарні арифметичні оператори.
Для операторів +, –, *, / виконуються відповідні операції додавання, відніманн, множення, ділення двох дробів. Оператор // (ділення націло) повертає дробове число від ділення операндів. Оператор % (взяття остачі) повертає ціле число від ділення операндів.

Клас містить метод Normal(), який приводить дріб до нормального виду на зразок

-8/-12 = 2/3

Текст програми наступний

# Перевантаження бінарного оператора +

# Клас, що описує дріб
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

    # Методи доступу до полів self.num, self.denom
    def GetNum(): return self.num
    def GetDenom(): return self.denom
    def Set(self, num, denom):
        self.num = num
        self.denom = denom
        return

    #-------------- Методи перевантаження операторів --------------
    # Перевантаження бінарного оператора + (додавання дробів) - метод __add__()
    def __add__(self, frac):
        obj = Fraction((self.num*frac.denom+self.denom*frac.num), self.denom*frac.denom)
        return obj

    # Перевантаження бінарного оператора віднімання - метод __sub__()
    def __sub__(self, frac):
        # віднімання дробів
        obj = Fraction((self.num*frac.denom-self.denom*frac.num), self.denom*frac.denom)
        return obj

    # Перевантаження бінарного * (множення) - метод __mul__()
    def __mul__(self, frac):
        obj = Fraction(self.num*frac.num, self.denom*frac.denom)
        return obj

    # Перевантаження бінарного / (ділення) - метод __div__()
    def __div__(self, frac):
        obj = Fraction(self.num*frac.denom, self.denom*frac.num)
        return obj

    # Перевантаження бінарного // (ділення націло) - метод __floordiv__()
    def __floordiv__(self, frac):
        # Метод повертає результат ділення типу float
        return float((self.num*frac.denom) / (self.denom*frac.num))

    # Перевантаження бінарного оператора % (взяття остачі) - метод __mod__()
    def __mod__(self, frac):
        # Метод повертає результат ділення типу int
        return int((self.num*frac.denom) / (self.denom*frac.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(6, -12)
f1.Print("f1")
f2 = Fraction(2, -12)
f2.Print("f2")

f3 = f1 + f2
f3.Print("f1 + f2")

f3 = f1 - f2
f3.Print("f1 - f2")

f3 = f1 * f2
f3.Print("f1 * f2")

f3 = f1 / f2
f3.Print("f1 / f2")

res = f1 // f2
print("f1 // f2 => ", res) # res = 3.0

res = f1 % f2
print("f1 % f2 => ", res) # res = 3

Результат

f1 => 1 / -2
f2 => 1 / -6)
f1 + f2 => -2 / 3
f1 - f2 => -1 / 3
f1 * f2 => 1 / 12
f1 / f2 => 3 / 1)
f1 // f2 => 3.0
f1 % f2 => 3

   


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