🖥 Что такое перегрузка операторов? Есть ли перегрузка операторов в Python



Перегрузка операторов в Python – это возможность с помощью специальных методов в классах переопределять различные операторы языка. Имена таких методов включают двойное подчеркивание спереди и сзади.



Под операторами в данном контексте понимаются не только знаки +, -, *, /, обеспечивающие операции сложения, вычитания и др., но также специфика синтаксиса языка, обеспечивающая операции создания объекта, вызова объекта как функции, обращение к элементу объекта по индексу, вывод объекта и другое



На самом деле перегрузка операторов в пользовательских классах используется не так часто, если не считать конструктора. Но сам факт наличия такой особенности объектно-ориентированного программирования, требует отдельного рассмотрения темы.



Возможность перегрузки операторов обеспечивает схожесть пользовательского класса со встроенными классами Python. Ведь все встроенные типы данных Питона – это классы. В результате все объекты могут иметь одинаковые интерфейсы. Так если ваш класс предполагает обращение к элементу объекта по индексу, например a[0], то это можно обеспечить.



Пусть будет класс-агрегат B, содержащий в списке объекты класса A:



class A:

def __init__(self, arg):

self.arg = arg



def __str__(self):

return str(self.arg)





class B:

def __init__(self, *args):

self.aList = []

for i in args:

self.aList.append(A(i))





group = B(5, 10, 'abc')



Чтобы получить элемент списка, несомненно, мы можем обратиться по индексу к полю aList:



print(group.aList[1])



Однако куда интереснее извлекать элемент по индексу из самого объекта, а не из его поля:



class B:

def __init__(self, *args):

self.aList = []

for i in args:

self.aList.append(A(i))



def __getitem__(self, i):

return self.aList[i]





group = B(5, 10, 'abc')

print(group.aList[1]) # выведет 10

print(group[0]) # 5

print(group[2]) # abc




Это делает объекты класса B похожими на объекты встроенных в Python классов-последовательностей (списков, строк, кортежей). Здесь метод __getitem__() перегружает операцию извлечения элемента по индексу. Другими словами, этот метод вызывается, когда к объекту применяется операция извлечения элемента: объект[индекс].



Бывает необходимо, чтобы объект вел себя как функция. Это значит, если у нас есть объект a, то мы можем обращаться к нему в нотации функции, т. е. ставить после него круглые скобки и даже передавать в них аргументы:



a = A()

a()

a(3, 4)




Метод __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 объекта.



@python_job_interview