Python позволяет определять для своих классов встроенные операторы, такие как операции сложения, вычитания и т.д. Для этого в модуле operator определен ряд функций:
Операция |
Синтаксис |
Функция |
Сложение |
|
|
Объединение |
|
|
Проверка наличия |
|
|
Деление |
|
|
Деление |
|
|
Поразрядное И |
|
|
Поразрядное XOR |
|
|
Поразрядная инверсия |
|
|
Поразрядное ИЛИ |
|
|
Степень |
|
|
Присвоение по индексу |
|
|
Удаление по индексу |
|
|
Обращение по индексу |
|
|
Сдвиг влево |
|
|
Остаток от деления |
|
|
Умножение |
|
|
Умножение матриц |
|
|
Арифметическое отрицание |
|
|
Логическое отрицание |
|
|
Положительное значение |
|
|
Сдвиг вправо |
|
|
Установка диапазона |
|
|
Удаление диапазона |
|
|
Получение диапазона |
|
|
Вычитание |
|
|
Проверка на Truе/False |
|
|
Меньше чем |
|
|
Меньше чем или равно |
|
|
Равенство |
|
|
Неравенство |
|
|
Больше чем или равно |
|
|
Больше чем |
|
|
Сложение с присваиванием |
|
|
Объединение с присваиванием |
|
|
Поразрядное умножение с присваиванием |
|
|
Деление с присваиванием |
|
|
Сдвиг влево с присваиванием |
|
|
Сдвиг вправо с присваиванием |
|
|
Деление по модулю с присваиванием |
|
|
Умножение с присваиванием |
|
|
Умножение матриц с присваиванием |
|
|
Поразрядное сложение с присваиванием |
|
|
Возведение в степень с присваиванием |
|
|
Вычитание с присваиванием |
|
|
Деление с присваиванием |
|
|
Операция XOR с присваиванием |
|
|
Чтобы определить оператор для некоторого класса, данный класс должен реализовать соответствующую функцию. Так, для определения оператора сложения применяется функция __add__(), поэтому внутри класса нам надо определить данную функцию. Например:
class Counter: def __init__(self, value): self.value = value # переопределение оператора сложения def __add__(self, other): return Counter(self.value + other.value) counter1 = Counter(5) counter2 = Counter(15) counter3 = counter1 + counter2 print(counter3.value) # 20
Здесь определен класс Counter, который имеет атрибут value - условное некоторое число. С помощью функции __add__
определяем для типа Counter оператор сложения. Допустим, мы хотим, чтобы
один объект Counter можно было сложить с другим объектом Counter. В этом случае второй параметр функции будет представлять другой объект Counter:
def __add__(self, other): return Counter(self.value + other.value)
В результате возвращаем новый объект Counter, в который помещается сумма атрибутов value обоих объектов.
После этого мы сможем складывать два объекта Counter, и результатом сложения будет новый объект Counter.
Причем в данном случае реализован не единственно возможный вариант оператора сложения. Так, в примере выше второй параметр функции представлял другой объект Counter. Но в реалньости это может быть любой тип. Например, что, если мы хотим складывать Counter не с другим объектом Counter, а с числом. Тогда мы могли определить следующий оператор:
class Counter: def __init__(self, value): self.value = value def __add__(self, other): return Counter(self.value + other) counter1 = Counter(5) counter3 = counter1 + 6 print(counter3.value) # 11
Здесь оператор сложения по прежнему возвращает объект Counter, только теперь второй параметр представляет обычное число.
Возвращаемый тип ряда операторов также жестко не определен. Например, мы могли бы возвращить также обычное число:
class Counter: def __init__(self, value): self.value = value def __add__(self, other): return self.value + other counter1 = Counter(5) result = counter1 + 7 print(result) # 12
Рассмотрим еще ряд примеров определения операторов.
Определение функции __bool__ позволяет установить истинность объекта или фактически преобразовать объект к значениям True/False. Например:
class Counter: def __init__(self, value): self.value = value def __bool__(self): return self.value > 0 def test(counter): if counter: print("Counter = True") else: print("Counter = False") counter1 = Counter(3) test(counter1) # Counter = True counter2 = Counter(-3) test(counter2) # Counter = False
В данном случае будем считать, что, если значение value в Counter меньше 1, то объект Counter будет рассматриваться как False, а при положительных значениях - как True. Благодаря этому мы можем использовать объект Counter в условных или циклических конструкциях. Так, в примере выше для тестирования определена функция test, которая в конструкции if..else проверяет значение объекта Counter и в зависимости от результата проверки выводит определенное сообщение на консоль.
Или, например, мы могли бы использовать объект Counter в цикле while в качестве условия:
class Counter: def __init__(self, value): self.value = value def __bool__(self): return self.value > 0 counter1 = Counter(3) while(counter1): print("Counter1: ", counter1.value) counter1.value -=1
В данном случае цикл while будет выполняться, пока counter1 соответствует значению True (по сути покак его значение value больше 0)
Ряд операций призваны возвращать логическое значение True или False. Например, операции сравнения:
class Counter: def __init__(self, value): self.value = value def __gt__(self, other): return self.value > other.value def __lt__(self, other): return self.value < other.value counter1 = Counter(1) counter2 = Counter(2) if counter1 > counter2: print("counter1 больше чем counter2") elif counter1 < counter2: print("counter1 меньше чем counter2") else: print("counter1 и counter2 равны")
Здесь в классе Counter определены операторы < (функция __lt__()
) и > (функция __gt__()
). В данном случае сравниваем с другим объектом Counter. В реальности
же сравниваем значения атрибутов двух объектов.
def __gt__(self, other): return self.value > other.value def __lt__(self, other): return self.value < other.value
Затем мы можем применять соответствующие операции к двум объектам Counter:
if counter1 > counter2:
Ряд операторов позволяют обращаться к объекту по индексу, используя квадратные скобки:
obj[index]
Обычно подобные операции применяются по отношению к коллекциям, которые будут рассмотрены в последующих статьях. Например, можно использовать подобные операции для получения или изменения какого-то элемента списка значений. В реальности эти операции могут применяться к любому объекту, а используемый индекс также может представлять все что угодно. Рассмотрим операции обращения по индексу на примере получения значения по индексу:
class Person: def __init__(self, name, age): self.__name = name self.__age = age def __getitem__(self, prop): if prop == "name": return self.__name elif prop == "age": return self.__age return None tom = Person("Tom", 39) print("Name:", tom["name"]) # Name: Tom print("Age:", tom["age"]) # Age: 39 print("Id:", tom["id"]) # Id: None
Итак, здесь определен класс Person, содержит два приватных поля - __name и __age. Для реализации получения данных по индексу определена функция __getitem__(). В качестве второго параметра эту функцию передается значение, которое выполняет роль индекса. В нашем случае это будет название атрибута. И в зависимости от переданного значения возвращаем либо значение атрибута __name, либо значение атрибута __age. Если передано невалидное названия атрибута, то возвращаем None.
Для получения значения по индесу передаем индекс - название атрибута в квадратных скобках:
tom["name"]
Оператор in позволяет проверить наличие определенного значения в последовательности - некотором наборе значений:
значение in последовательность
Если значение присутствует в последовательности, то возвращается True, иначе возвращается False. Например, проверим наличие свойства в объекте:
class Person: def __init__(self, name, age): self.name = name self.age = age def __contains__(self, prop): if prop == "name" or prop == "age": return True return False tom = Person("Tom", 39) print("name" in tom) # True print("id" in tom) # False
За реализацию оператора in отвечает функция __contains__(). В качестве первого параметра, как обычно, указывается текущий объект - тот объект, который стоит справа от оператора in. А в качестве второго параметра - проверяемое значение - оно указывается слева от in. В данном случае если второй параметр - равен "name" или "age", то возвращаем True. Что означает, что атрибут есть в объекте.
Соответственно выражение "name" in tom
возвратит True, а выражение "id" in tom
возвратит False.
Некоторые операторы - операторы сравения удобнее реализовать парами. Если мы реализуем оператор ==, то можно сразу реализовать и оператор !=. Причем чтобы не прописывать одну и ту же логику по два раза, можно реализовать один оператор через другой:
class Counter: def __init__(self, value): self.value = value def __eq__(self, other): return self.value == other.value def __ne__(self, other): return not (self == other) def __gt__(self, other): return self.value > other.value def __le__(self, other): return not (self > other) def __lt__(self, other): return self.value < other.value def __ge__(self, other): return not (self < other) c1 = Counter(1) c2 = Counter(2) print(c1 == c2) # False print(c1 != c2) # True print(c1 < c2) # True print(c1 >= c2) # False
В данном случае оператора != возвращает инверсию результата оператора ==, который определен выше
def __eq__(self, other): return self.value == other.value def __ne__(self, other): return not (self == other)
Аналогично определены операторы < и >=, а также > и <=.