Рубрики
Без рубрики

Перегрузка функций и операторов в Python

Автор оригинала: Nicholas Samuel.

Что такое Перегрузка?

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

Перегрузка метода способствует повторному использованию. Например, вместо того, чтобы писать несколько методов, которые отличаются лишь незначительно, мы можем написать один метод и перегрузить его. Перегрузка также улучшает четкость кода и устраняет сложность.

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

В оставшемся разделе этой статьи мы подробно обсудим перегрузку функций и операторов.

Перегрузка функций в Python

В зависимости от того, как была определена функция, мы можем вызвать ее с нулем, одним, двумя или даже многими параметрами. Это называется “перегрузкой функций”.

Перегрузка функций далее делится на два типа: перегрузка встроенных функций и перегрузка пользовательских функций. Мы рассмотрим оба типа в следующих разделах.

Перегрузка встроенных функций

Мы можем изменить поведение встроенных функций Python по умолчанию. Нам нужно только определить соответствующий специальный метод в нашем классе.

Давайте продемонстрируем это с помощью функции Python len() в нашем классе Purchase:

class Purchase:
    def __init__(self, basket, buyer):
        self.basket = list(basket)
        self.buyer = buyer

    def __len__(self):
        return len(self.basket)

purchase = Purchase(['pen', 'book', 'pencil'], 'Python')
print(len(purchase))

Выход:

3

Чтобы изменить поведение функции len () , мы определили в нашем классе специальный метод с именем _len_ () . Каждый раз , когда мы передаем объект нашего класса в len () , результат будет получен путем вызова нашей пользовательской функции, то есть _len_() .

Вывод показывает, что мы можем использовать len() для получения длины корзины.

Если мы вызовем len() на объекте без перегруженной функции __len__ () , мы получим TypeError, как показано ниже:

class Purchase:
    def __init__(self, basket, buyer):
        self.basket = list(basket)
        self.buyer = buyer

purchase = Purchase(['pen', 'book', 'pencil'], 'Python')
print(len(purchase))

Выход:

Traceback (most recent call last):
  File "C:/Users/admin/func.py", line 8, in 
    print(len(purchase))
TypeError: object of type 'Purchase' has no len()

Примечание: Python ожидает, что функция len() вернет целое число, поэтому это следует учитывать при перегрузке функции. Если ожидается, что ваша перегруженная функция вернет что-либо еще, кроме целого числа, вы получите TypeError.

Мы можем изменить поведение метода len() в приведенном выше примере из определения его реализации, то есть __len__() . Вместо того чтобы возвращать длину корзины, давайте сделаем так, чтобы она возвращала что-то другое:

class Purchase:
    def __init__(self, basket, buyer):
        self.basket = list(basket)
        self.buyer = buyer

    def __len__(self):
        return 10;

purchase = Purchase(['pen', 'book', 'pencil'], 'Python')
print(len(purchase))

Выход:

10

Вместо того, чтобы возвращать длину корзины, он теперь возвращает значение, которое мы указали.

Перегрузка Пользовательских Функций

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

class Student:
    def hello(self, name=None):
        if name is not None:
            print('Hey ' + name)
        else:
            print('Hey ')

# Creating a class instance
std = Student()

# Call the method
std.hello()

# Call the method and pass a parameter
std.hello('Nicholas')

Выход:

Hey
Hey Nicholas

Мы создали класс Student с одной функцией с именем hello() . Класс принимает параметр name , который был установлен в None . Это означает, что метод может быть вызван с параметром или без него.

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

Теперь мы знаем, как работает перегрузка функций, следующий раздел посвящен перегрузке операторов.

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

Python позволяет нам изменять поведение оператора по умолчанию в зависимости от используемых нами операндов. Эта практика называется “перегрузкой оператора”.

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

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

Чтобы увидеть перегрузку оператора Python в действии, запустите терминал Python и выполните следующие команды:

>>> 4 + 4
8
>>> "Py" + "thon"
'Python'

В первой команде мы использовали оператор “+” для сложения двух чисел. Во второй команде мы использовали тот же оператор для объединения двух строк.

В этом случае оператор “+” имеет две интерпретации. Когда он используется для сложения чисел, его называют “оператором сложения”. При использовании для добавления строк он называется “оператор конкатенации”. Короче говоря, мы можем сказать, что оператор “+” был перегружен для классов int и str .

Чтобы достичь перегрузки оператора, мы определяем специальный метод в определении класса. Имя метода должно начинаться и заканчиваться двойным подчеркиванием (__). Оператор + перегружается с помощью специального метода с именем __add__() . Этот метод реализуется как классами int , так и str .

Рассмотрим следующее выражение:

x + y

Python интерпретирует выражение как x.__и__(y) . Вызываемая версия __add__() будет зависеть от типов x и y . Например:

>>> x, y = 5, 7

>>> x + y

12
>>> x.__add__(y)
12
>>>

В приведенном выше примере показано, как использовать оператор+, а также его специальный метод.

В следующем примере показано, как перегружать различные операторы в Python:

import math

class Point:

    def __init__(self, xCoord=0, yCoord=0):
        self.__xCoord = xCoord
        self.__yCoord = yCoord

    # get x coordinate
    def get_xCoord(self):
        return self.__xCoord

    # set x coordinate
    def set_xCoord(self, xCoord):
        self.__xCoord = xCoord

    # get y coordinate
    def get_yCoord(self):
        return self.__yCoord

    # set y coordinate
    def set_yCoord(self, yCoord):
        self.__yCoord = yCoord

    # get current position
    def get_position(self):
        return self.__xCoord, self.__yCoord

    # change x & y coordinates by p & q
    def move(self, p, q):
        self.__xCoord += p
        self.__yCoord += q

    # overload + operator
    def __add__(self, point_ov):
        return Point(self.__xCoord + point_ov.__xCoord, self.__yCoord + point_ov.__yCoord)

    # overload - operator
    def __sub__(self, point_ov):
        return Point(self.__xCoord - point_ov.__xCoord, self.__yCoord - point_ov.__yCoord)

    # overload < (less than) operator
    def __lt__(self, point_ov):
        return math.sqrt(self.__xCoord ** 2 + self.__yCoord ** 2) < math.sqrt(point_ov.__xCoord ** 2 + point_ov.__yCoord ** 2)

    # overload > (greater than) operator
    def __gt__(self, point_ov):
        return math.sqrt(self.__xCoord ** 2 + self.__yCoord ** 2) > math.sqrt(point_ov.__xCoord ** 2 + point_ov.__yCoord ** 2)

    # overload <= (less than or equal to) operator
    def __le__(self, point_ov):
        return math.sqrt(self.__xCoord ** 2 + self.__yCoord ** 2) <= math.sqrt(point_ov.__xCoord ** 2 + point_ov.__yCoord ** 2)

    # overload >= (greater than or equal to) operator
    def __ge__(self, point_ov):
        return math.sqrt(self.__xCoord ** 2 + self.__yCoord ** 2) >= math.sqrt(point_ov.__xCoord ** 2 + point_ov.__yCoord ** 2)

    # overload == (equal to) operator
    def __eq__(self, point_ov):
        return math.sqrt(self.__xCoord ** 2 + self.__yCoord ** 2) == math.sqrt(point_ov.__xCoord ** 2 + point_ov.__yCoord ** 2)

point1 = Point(2, 4)
point2 = Point(12, 8)

print("point1 < point2:", point1 < point2)
print("point1 > point2:", point1 > point2)
print("point1 <= point2:", point1 <= point2)
print("point1 >= point2:", point1 >= point2)
print("point1 == point2:", point1 == point2)

Выход:

point1 < point2: True
point1 > point2: False
point1 <= point2: True
point1 >= point2: False
point1 == point2: False

У нас есть два частных атрибута в классе точек, а именно: __xCoord и __yCoord , представляющие декартовы координаты плоскости с именем xCoord и yCoord . Мы определили методы setter и getter для этих атрибутов. Метод get_position() помогает нам получить текущую позицию, в то время как метод move() помогает нам изменить координаты.

Рассмотрим следующую строку, извлеченную из кода:

    def __add__(self, point_ov):

Эта строка помогает нам перегружать оператор + для нашего класса. Метод __add__() должен создать новый точечный объект, добавив отдельные координаты одного точечного объекта к другому точечному объекту. Наконец, он возвращает вновь созданный объект вызывающему объекту. Это помогает нам писать такие выражения, как:

point3 = point1 + point2

Python интерпретирует вышеизложенное как пункт 3.__add__(point2) . Затем он вызовет метод __add__() для добавления двух точечных объектов. Результат будет отнесен к “пункту 3”.

Обратите внимание, что после вызова метода __add__() значение point 1 будет присвоено параметру self , а значение point2d будет присвоено параметру point_ov . Все другие специальные методы будут работать аналогичным образом.

Операторы для перегрузки

В следующей таблице показаны некоторые из наиболее часто перегружаемых математических операторов и метод класса для перегрузки:

__add__(self, other) +
__sub__(self, other)
__mul__(self, other) *
__truediv__(self, other) /
__mod__(self, other) %
__lt__(self, other) <
__le__(self, other) <=< код>
__eq__(self, other) ==
__ne__(self, other) !=
__gt__(self, other) >
__ge__(self, other) >=

Вывод

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