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

Мы можем легко найти минимальное число, сумму чисел или отсортировать последовательность:

>>> a = [3, 7, -1, 10]
>>> min(a)
-1
>>> sorted(a)
[-1, 3, 7, 10]
>>> sum(a)
19

Хочется, чтобы эти функции работали и для классов. Для этого нужно, чтобы классы умели сравнивать < (для min и sorted), и складывать через + (для sum).

Мы научились, чтобы print могла печатать экземпляры класса. Для этого мы в классе пишем функцию __str__(self). Если есть класс А, и x = A() - экземпляр класса А, то при print(x) вызывается str(x), которая вызывает x.__str__() print([x]) вызовет функцию repr(x), которая вызовет x.__repr__()

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

Можно переопределить в классе функции, чтобы работали операторы:

Специальная функция Оператор Значение
__lt__(self, other) x < y Возвращает True, если х меньше, чем у
__le__(self, other) x <= y Возвращает True, если х меньше или равно у
__eq__(self, other) x == y Возвращает True, если х равно у
__ne__(self, other) x != y Возвращает True, если х НЕ равно у
__gt__(self, other) x > y Возвращает True, если х больше, чем у
__ge__(self, other) x >= y Возвращает True, если х больше или равно у
Специальная функция Оператор Коментарий
__add__(self, other) x + y
__sub__(self, other) x - y
__mul__(self, other) x * y
__truediv__(self, other) x / y
__floordiv__(self, other) x // y
__mod__(self, other) x % y
__pow__(self, other) x ** y

Вспомним умножение строки на число 'hi'*3. Можно написать 3*'hi', получим такой же результат.

Для того, чтобы написать функцию число * строку, нужно переопределить для строки метод __rmul__ .

some_object + other

Вызывает __add__()

other + some_object

Вызывает __radd__(). У нее первый операнд other, а второй self.

Ее можно реализовать как:

def __radd__(self, other):
    return __add__(other, self)

Пример с точкой на плоскости XY

В классе Point (точка на плоскости ХУ) переопределим функции для == и для <

class Point(object):
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def __str__(self):
        return '({} {})'.format(self.x, self.y)

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

    def __lt__(self, other):
        """ Меньше та точка, у которой меньше х. При одинаковых x, та, у которой меньше y."""
        if self.x == other.x:
            return self.y < other.y
        return self.x < other.x

    # другие функции класса: move, dir, dist...

# Тестируем функции класса:
def test():
    p0 = Point(3, 5)
    p1 = Point(3, 5)
    p2 = Point(-1, 7)
    p3 = Point(3, 1.17)

    print('p0=', p0)       # 3 5
    print('p1=', p1)       # 3 5
    print('p2=', p2)       # -1 7
    print('p3=', p3)       # 3 1.17

    print('p0 == p1', p0 == p1) # True
    assert(p0 == p1)
    print('p1 == p2', p1 == p2) # False
    assert(not p1 == p2)

    print('p0 != p1', p0 != p1) # False
    assert(not(p0 != p1))
    print('p1 != p2', p1 != p2) # True
    assert(p1 != p2)

    print('p2 < p1', p2 < p1)   # True
    assert(p2 < p1)
    print('p1 < p2', p1 < p2)   # False
    assert(not(p1 < p2))

    print('p3 < p1', p3 < p1)   # True
    assert(p3 < p1)
    print('p1 < p3', p1 < p3)   # False
    assert(not (p1 < p3))

    a = [p0, p1, p2, p3]
    pmin = min(a)
    print('pmin =', pmin)
    assert(p2 == pmin)

    b = sorted(a)
    print(b)
    assert(b == [p2, p3, p0, p1])

test()

results matching ""

    No results matching ""