Перегрузка операторов python пример

Перегрузка операторов в Python

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

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

Мы уже использовали ряд методов перегрузки операторов. Это

  • __init__() – конструктор объектов класса, вызывается при создании объектов Конструктор класса и его вызов
  • __del__() – деструктор объектов класса, вызывается при удалении объектов
  • __str__() – преобразование объекта к строковому представлению, вызывается, когда объект передается функциям print() и str()
  • __add__() – метод перегрузки оператора сложения, вызывается, когда объект участвует в операции сложения будучи операндом с левой стороны __add__ - метод перегрузки оператора сложения
  • __setattr__() – вызывается, когда атрибуту объекта выполняется присваивание __setattr__ - метод перегрузки оператора присваивания

В 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 :

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

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__ перегружает операцию извлечения элемента по индексу. Другими словами, этот метод вызывается, когда к объекту применяется операция извлечения элемента: объект[индекс] .

Читайте также:  Text editor with java

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

Метод __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 кроме метода __str__ есть схожий с ним по поведению, но более «низкоуровневый» метод __repr__ . Оба метода должны возвращать строку.

Если в классе есть только метод __str__() , то при обращении к объекту в интерпретаторе без функции print() , он не будет вызываться:

>>> class A: . def __str__(self): . return "This is object of A" . >>> a = A() >>> print(a) This is object of A >>> a >>> str(a) 'This is object of A' >>> repr(a) ''

Метод __str__() вызывается при попытке преобразования объекта в строку с помощью встроенной функции str() . А функция print() так устроена, что сама вызывает str() для своих аргументов.

В Python есть встроенная функция repr() , которая также как str() преобразует объект в строку. Но «сырую» строку. Что это значит, попробуем понять с помощью примера:

>>> a = '3 + 2' >>> b = repr(a) >>> a '3 + 2' >>> b "'3 + 2'" >>> eval(a) 5 >>> eval(b) '3 + 2' >>> c = "Hello\nWorld" >>> d = repr(c) >>> c 'Hello\nWorld' >>> d "'Hello\\nWorld'" >>> print(c) Hello World >>> print(d) 'Hello\nWorld'

Функция eval() преобразует переданную строку в программный код, который тут же выполняется. Функция print() выполняет переход на новую строку, если встречает символ \n . Функция repr() выполняет действия, направленные на своего рода защиту строки от интерпретации, оставляет ее «сырой», т. е. в исходном виде. Еще раз:

>>> c = "Hello\nWorld" >>> c # аналог print(repr(c)) 'Hello\nWorld' >>> print(c) # аналог print(str(c)) Hello World

Если для вашего класса различия между сырым и обычным строковым представлением экземпляров не важны, желательно определять только метод __repr__ . Он будет вызываться для всех случаев преобразования к строке:

>>> class A: . def __repr__(self): . return "It's obj of A" . >>> a = A() >>> a It's obj of A >>> repr(a) "It's obj of A" >>> str(a) "It's obj of A" >>> print(a) It's obj of A

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

Читайте также:  Php вывод всего xml

Практическая работа

Напишите класс Snow по следующему описанию.

В конструкторе класса инициируется поле, содержащее количество снежинок, выраженное целым числом.

Класс включает методы перегрузки арифметических операторов: __add__ – сложение, __sub__ – вычитание, __mul__ – умножение, __truediv__ – деление. В классе код этих методов должен выполнять увеличение или уменьшение количества снежинок на число n или в n раз. Метод __truediv__ перегружает обычное / , а не целочисленное // деление. Однако пусть в методе происходит округление значения до целого числа.

Класс включает метод make_snow , который помимо self принимает число снежинок в ряду и возвращает строку вида «*****\n*****\n*****…» , где количество снежинок между ‘\n’ равно переданному аргументу, а количество рядов вычисляется, исходя из общего количества снежинок.

Вызов экземпляра класса Snow в нотации функции с одним аргументом, должен приводить к перезаписи значения поля, в котором хранится количество снежинок, на переданное в качестве аргумента значение.

Курс с примерами решений практических работ:
pdf-версия

Объектно-ориентированное программирование на Python

Источник

Перегрузка операторов в Python

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

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

Различные варианты использования основных арифметических операторов

# Program to show use of # + operator for different purposes. print(5 + 5) # concatenate two strings print("Safa"+"Mulani") # Product two numbers print(10 * 10) # Repeat the String print("Safa"*4)
10 SafaMulani 100 SafaSafaSafaSafa

Как перегрузить оператор в Python?

Для выполнения перегрузки оператора Python предоставляет некоторую специальную функцию, которая автоматически вызывается, когда она связана с этим конкретным оператором. Например, когда мы используем оператор +, автоматически вызывается метод __add__ , в котором определяется операция для оператора +.

Читайте также:  Python file opening mode

Специальные функции в Python

Глобальные функции, начинающиеся с двойного подчеркивания __, в Python называются специальными функциями. Это потому, что они необычные. Одна из них — функция __init __(), которую мы обычно определяем и напоминаем как конструктор. Он вызывается каждый раз, когда мы создаем новый объект этого класса.

Для двоичных операторов в Python

Оператор Метод
+ __add__(self, other)
__sub__(self, other)
* __mul__(self, other)
/ __truediv__(self, other)
// __floordiv__(self, other)
% __mod__(self, other)
** __pow__(self, other)

Для операторов сравнения в Python

Оператор Метод
__lt__(self, other)
> __gt__(self, other)
__le__(self, other)
>= __ge__(self, other)
== __eq__(self, other)
!= __ne__(self, other)

Для операторов присваивания

Оператор Метод
-= __isub__(self, other)
+= __iadd__(self, other)
*= __imul__(self, other)
/= __idiv__(self, other)
//= __ifloordiv__(self, other)
%= __imod__(self, other)
**= __ipow__(self, other)

Для унарных операторов

Перегрузка бинарного оператора

Когда мы используем оператор +, автоматически вызывается волшебный метод __add__ , в котором определяется операция для оператора +. Следовательно, изменяя код метода, мы можем придать альтернативное значение оператору +.

# Program to overload an binary + operator class X: def __init__(self, x): self.x = x # adding two objects def __add__(self, y): return self.x + y.x ob1 = X(5) ob2 = X(5) ob3 = X("Safa") ob4 = X("Mulani") print(ob1 + ob2) # simple addition of objects print(ob3 + ob4) # concatenation of strings through object addition

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

class X: def __init__(self, x): self.x = x def __lt__(self, other): # Overloading < operator if(self.x
ob1 is less than ob2 Not equal

Пример

class Animal: def __init__(self, age): self.__age = age def setage(self, age): self.__age = age def getage(self): return self.__age def __add__(self, predict): return Animal( self.__age + predict.__age ) def __gt__(self, predict): return self.__age > predict.__age def __lt__(self, predict): return self.__age < predict.__age def __str__(self): return "Animal with original age " + str(self.__age) c1 = Animal(5) print(c1.getage()) c2 = Animal(5) print(c2.getage()) c3 = c1 + c2 print(c3.getage()) print( c3 >c2) print( c1 < c2) print(c3)
5 5 10 True False Animal with original age 10

Источник

Оцените статью