Перегрузка операторов — один из способов реализации полиморфизма, когда мы можем задать свою реализацию какого-либо метода в своём классе. Например, у нас есть два класса: class A: def go(self): print('Go, A!') class B(A): def go(self, name): print('Go, {}!'.format(name)) В данном примере класс B наследует класс A, но переопределяет метод go, поэтому он имеет мало общего с аналогичным методом класса A. Однако в python имеются методы, которые, как правило, не вызываются напрямую, а вызываются встроенными функциями или операторами. Например, метод __init__ перегружает конструктор класса. Конструктор - создание экземпляра класса.
>>> class A:
... def __init__(self, name):
... self.name = name
...
>>> a = A('Vasya')
>>> print(a.name)
Vasya
Собственно, далее пойдёт список таких "магических" методов. __new__(cls[, ...]) — управляет созданием экземпляра. В качестве обязательного аргумента принимает класс (не путать с экземпляром). Должен возвращать экземпляр класса для его последующей его передачи методу __init__. __init__(self[, ...]) - как уже было сказано выше, конструктор. __del__(self) - вызывается при удалении объекта сборщиком мусора. __repr__(self) - вызывается встроенной функцией repr; возвращает "сырые" данные, использующиеся для внутреннего представления в python. __str__(self) - вызывается функциями str, print и format. Возвращает строковое представление объекта. __bytes__(self) - вызывается функцией bytes при преобразовании к байтам. __format__(self, format_spec) - используется функцией format (а также методом format у строк). __lt__(self, other) - x < y вызывает x.__lt__(y). __le__(self, other) - x ≤ y вызывает x.__le__(y). __eq__(self, other) - x == y вызывает x.__eq__(y). __ne__(self, other) - x != y вызывает x.__ne__(y) __gt__(self, other) - x > y вызывает x.__gt__(y). __ge__(self, other) - x ≥ y вызывает x.__ge__(y). __hash__(self) - получение хэш-суммы объекта, например, для добавления в словарь. __bool__(self) - вызывается при проверке истинности. Если этот метод не определён, вызывается метод __len__ (объекты, имеющие ненулевую длину, считаются истинными). __getattr__(self, name) - вызывается, когда атрибут экземпляра класса не найден в обычных местах (например, у экземпляра нет метода с таким названием). __setattr__(self, name, value) - назначение атрибута. __delattr__(self, name) - удаление атрибута (del obj.name). __call__(self[, args...]) - вызов экземпляра класса как функции. __len__(self) - длина объекта. __getitem__(self, key) - доступ по индексу (или ключу). __setitem__(self, key, value) - назначение элемента по индексу. __delitem__(self, key) - удаление элемента по индексу. __iter__(self) - возвращает итератор для контейнера. __reversed__(self) - итератор из элементов, следующих в обратном порядке. __contains__(self, item) - проверка на принадлежность элемента контейнеру (item in self). Перегрузка арифметических операторов__add__(self, other) - сложение. x + y вызывает x.__add__(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). __divmod__(self, other) - частное и остаток (divmod(x, y)). __pow__(self, other[, modulo]) - возведение в степень (x ** y, pow(x, y[, modulo])). __lshift__(self, other) - битовый сдвиг влево (x << y). __rshift__(self, other) - битовый сдвиг вправо (x >> y). __and__(self, other) - битовое И (x & y). __xor__(self, other) - битовое ИСКЛЮЧАЮЩЕЕ ИЛИ (x ^ y). __or__(self, other) - битовое ИЛИ (x | y). Пойдём дальше. __radd__(self, other), __rsub__(self, other), __rmul__(self, other), __rtruediv__(self, other), __rfloordiv__(self, other), __rmod__(self, other), __rdivmod__(self, other), __rpow__(self, other), __rlshift__(self, other), __rrshift__(self, other), __rand__(self, other), __rxor__(self, other), __ror__(self, other) - делают то же самое, что и арифметические операторы, перечисленные выше, но для аргументов, находящихся справа, и только в случае, если для левого операнда не определён соответствующий метод. Например, операция x + y будет сначала пытаться вызвать x.__add__(y), и только в том случае, если это не получилось, будет пытаться вызвать y.__radd__(x). Аналогично для остальных методов. Идём дальше. __iadd__(self, other) - +=. __isub__(self, other) - -=. __imul__(self, other) - *=. __itruediv__(self, other) - /=. __ifloordiv__(self, other) - //=. __imod__(self, other) - %=. __ipow__(self, other[, modulo]) - **=. __ilshift__(self, other) - <<=. __irshift__(self, other) - >>=. __iand__(self, other) - &=. __ixor__(self, other) - ^=. __ior__(self, other) - |=. __neg__(self) - унарный -. __pos__(self) - унарный +. __abs__(self) - модуль (abs()). __invert__(self) - инверсия (~). __complex__(self) - приведение к complex. __int__(self) - приведение к int. __float__(self) - приведение к float. __round__(self[, n]) - округление. __enter__(self), __exit__(self, exc_type, exc_value, traceback) - реализация менеджеров контекста. Рассмотрим некоторые из этих методов на примере двухмерного вектора, для которого переопределим некоторые методы: import math class Vector2D: def __init__(self, x, y): self.x = x self.y = y def __repr__(self): return 'Vector2D({}, {})'.format(self.x, self.y) def __str__(self): return '({}, {})'.format(self.x, self.y) def __add__(self, other): return Vector2D(self.x + other.x, self.y + other.y) def __iadd__(self, other): self.x += other.x self.y += other.y return self def __sub__(self, other): return Vector2D(self.x - other.x, self.y - other.y) def __isub__(self, other): self.x -= other.x self.y -= other.y return self def __abs__(self): return math.hypot(self.x, self.y) def __bool__(self): return self.x != 0 or self.y != 0 def __neg__(self): return Vector2D(-self.x, -self.y) >>> x = Vector2D(3, 4) >>> x Vector2D(3, 4) >>> print(x) (3, 4) >>> abs(x) 5.0 >>> y = Vector2D(5, 6) >>> y Vector2D(5, 6) >>> x + y Vector2D(8, 10) >>> x - y Vector2D(-2, -2) >>> -x Vector2D(-3, -4) >>> x += y >>> x Vector2D(8, 10) >>> bool(x) True >>> z = Vector2D(0, 0) >>> bool(z) False >>> -z Vector2D(0, 0) В заключение хочу сказать, что перегрузка специальных методов - вещь хорошая, но не стоит ей слишком злоупотреблять. Перегружайте их только тогда, когда вы уверены в том, что это поможет пониманию программного кода. | |
| |
Просмотров: 795 | |
Всего комментариев: 0 | |