Перегрузка операторов в ООП. Урок 10

До этого мы говорили только о классах и объектах, которые создает программист (пользовательские классы). Однако Python настолько объектно-ориентированный язык, что в нем любые строка, число, список и др. являются по сути объектами, принадлежащими встроенным классам (типам данных): строкам, числам и др. Т. е. типы данных — это встроенные классы, а любые данные — это объекты.

Объектно-ориентированное программирование подразумевает не только наличие объектов, но и их взаимодействие между собой. Поэтому важно, чтобы к объектам разных классов можно было применить одну и туже операцию (например, сложение).

Для пользовательских классов предусмотрены специальные методы, позволяющие объектам данных классов участвовать в таких привычных операциях как сложение, вычитание, умножение, деление (+ - * /), а также во многих других. Другими словами, смысл (то, что он делает) знака + (или любого другого оператора) зависит от того, к каким объектам он применяется. Это называется перегрузкой операторов. В классах перегруженные операторы описываются с помощью специальных зарезервированных методов, которые в начале и в конце имеют по два знака подчеркивания. В уроке рассматриваются лишь некоторые из них. Кроме того, ранее был уже рассмотрен один такой метод — конструктор __init__, который автоматически вызывается при создании объектов класса.

Рассмотрим пример перегрузки операторов.

class Newclass:
     def __init__(self, base):
          self.base = base
     def __add__(self, a):
          self.base = self.base + a
     def __str__(self):
          return "%s !!! " % self.base
 
a = Newclass(10)
a + 20
print (a)
 
b = Newclass("yes")
b + "terday"
print (b)
 
c = Newclass([2,6,3])
c + [7, 1]
print (c)

В данном примере используется два метода (исключая __init__) перегрузки операторов: __add__и __str__. Метод __add__ вызывается в том случае, когда объект данного класса участвует в операции сложения (для чисел), конкатенации (для строк) и объединения (для списков). Метод __str__ вызывается, когда объект передается в качестве аргумента встроенной функции print (на самом деле не только ей) и представляет данные в виде строки.

Результат работы скрипта представленного выше будет таким:

30 !!! 
yesterday !!! 
[2, 6, 3, 7, 1] !!! 

Задание. Спешите пример, посмотрите как он работает. Дополните класс методами __mul__(вызывается при использовании объекта в операциях умножения) и __sub__ (вычитание). Вызовите данные методы с помощью соответствующих операций с объектами. Для каких объектов невозможно использовать метод __sub__?

__call__ - перегрузка вызова функции

Метод __call__ автоматически вызывается, когда к объекту обращаются как к функции. Например, здесь во второй строке произойдет вызов метода __call__ некогоКласса:

объект = некийКласс()
объект([возможные аргументы])

Другими словами, метод __call__ позволяет объектам вести себя как функции.

Пример:

class Changeable:
     def __init__(self, color):
          self.color = color
     def __call__(self, newcolor):
          self.color = newcolor
     def __str__(self):
          return "%s" % self.color
 
canvas = Changeable("green")
frame = Changeable("blue")
 
canvas("red")
frame("yellow")
 
print (canvas, frame)

В этом примере с помощью конструктора класса при создании объектов устанавливается их цвет. Если требуется его поменять, то достаточно обратиться к объекту как к функции и в качестве аргумента передать новый цвет. Такой обращение автоматически вызовет метод __call__(который, в данном случае, изменит атрибут color объекта).

Задание. Создайте класс с методом __call__, принимающим два параметра и производящим над ними те или иные математические операции. Создайте несколько объектов класса и, затем, обратитесь к ним как к функциям.

Рассмотренные в этом уроке методы перегрузки операторов лишь малая часть из существующих. Фактически все, что можно делать со встроенными типами (числами, словарями и др.), можно реализовать и для пользовательских типов (классов). Можно сказать, что перегрузка операторов обеспечивает единый интерфейс для встроенных и пользовательских типов (классов). Так, в первом примере можно видеть как "складываются" объект-число и объект класса Newclass.

Создано