Python. Overloading operators in classes. General information




Overloading operators in classes. General information. Operators overloading methods. Examples


Contents


Search other resources:

1. General information about operators overloading

In the Python programming language, classes (as opposed to modules) can override operators. This mechanism is called operators overloading. Operator overloading in a class – is a mapping to a Python language operator (for example, operator +, , *, etc.) of a corresponding method in order to call the code of that method when using the overloaded operator. In other words, operator overloading allows class objects to be used as operands in expressions or other built-in operations such as addition, multiplication, slicing, inference, etc. If an overloaded operator is called for a certain class object in the program, then the method is automatically called that implements the actions of this operator. Thus, when the operator + (addition) is overloaded, any actions can be programmed in the method that implements it, even subtraction, multiplication, or whatever. However, such code will not have logic, misleading the programmer himself. As usual, the method corresponding to the + operator must sum something.

Using the operator overloading mechanism in classes provides the following advantages:

  • class objects are more closely integrated into the object model of the Python language;
  • class objects act more naturally, just like built-in language objects;
  • it becomes possible to use class objects in combination with built-in types;
  • program code tends to be more readable.

Operator overloading in classes aims to create a convenient tool for other programmers who use these classes in their projects.

 

2. The principles underlying the operator overloading in classes

The operator overloading mechanism is based on the following principles:

  • when using operator overloading in a class, methods starting and ending with two underscores are used (for example, __add__(), __str__(), and others). These methods have a special purpose and well-defined (fixed) names for each operation;
  • as soon as the built-in operator (operation) is called, the corresponding method is called automatically. For example, when specifying an overridden + operator for a class object, the __add__() method will be automatically called. This method must be implemented in the class;
  • if you need to get the result of an operation for a class object, then in the class method this result is returned by the return operator;
  • most of the nested Python statements can be overridden in classes. Each operator has a corresponding name of the method that implements the overload;
  • if the override of some operator is not implemented in the class, it means that the instance (object) of this class does not support these operations. For example, if the __sub__() method is not implemented in a class, then the object of this class does not support the subtraction (X-Y) operation;
  • overriding in the operator class is not a required feature. In other words, the class does not have to contain operator override methods;
  • operator overloading in classes allows you to integrate these classes into the Python object model. Instances of classes fit better into the language interface and act like built-in types.

 

3. List of methods that can be overloaded

Below is a short list of methods that overload various operations. The methods are grouped into the following categories:

  • methods for all types of operations;
  • methods of overloading operators for working with collections;
  • methods for numeric operations in binary form;
  • methods for other operations on numbers;
  • methods for operations with descriptors;
  • methods for operations used with context managers.

 

3.1. Methods for all kinds of operations

This category defines the following methods:

  • __new__(cls [, arg]*) – called to create and return a new instance of the class;
  • __init__(self [, arg]*) – replaces the constructor of the class when instantiating the class;
  • __del__(self) – replaces the destructor when collecting an instance of a class in garbage;
  • __repr__(self) – called in operation repr(self);
  • __str__(self) – called in the str(self) or print(self) operation;
  • __format__(self, format_specification) – called by the built-in function format();
  • __bytes__(self) – called by bytes() function to return a string representation of the bytes type of self;
  • __hash__(self) – called when processing hashed collections;
  • __bool__(self) – used when checking a value for truth;
  • __call__(self [, arg]*) – used in the self(args) operation when calling an instance of a class as a function;
  • __getattr__(self, name) – called by reference self.name, where name is a character string indicating access to an undefined attribute;
  • __setattr__(self, name) – called in the operation self.name = value;
  • __delattr__(self, name) – called in the operation del self.name;
  • __lt__(self, other) – called when the condition is checked self<other;
  • __le__(self, other) – called when the condition is checked self<=other;
  • __eq__(self, other) – invoked when checking self==other;
  • __ne__(self, other) – invoked when checking self!=other;
  • __gt__(self, other) – invoked when checking self>other;
  • __ge__(self, other) – invoked when checking self>=other;
  • __slots__ – forms a control descriptor at the class level with reservation of space for declared attributes in class instances;
  • __instancecheck__(self, instance) – returns True for isinstance() if the instance is a direct or implicit instance of the class;
  • __subclasscheck__(self, subclass) – returns True for issubclass() if the subclass is to be considered a direct or implicit subclass of this class;
  • __dir__(self) – called in the dir(self) operation and returns a sequence of attribute names.

 

3.2. Methods of operator overloading work with collections

The list of methods used when overriding operators for working with collections, sequences and reflections:

  • __len__(self) – called in len() to get the size of the collection;
  • __contains__(self, item) – called in the item in self operation to check if item is in the self collection;
  • __iter__(self) – called in operation iter(self);
  • __next__(self) – called by the built-in function next(self) in an iteration loop;
  • __getitem__(self, key) – called in operations self[key], self[i:j:k], x in self;
  • __setitem__(self, key, value) – called in operations self[key] = value and self[i:j:k]=value;
  • __delitem__(self, key) – called in operations del self[key] and del self[i:j:k];
  • __reversed__(self) – called by the built-in reversed() function to reverse the collection.

 

3.3. Methods for numeric operations in binary form

Methods for operations on binary numbers are divided into subgroups, which are described below.

3.3.1. Basic methods for operations on binary numbers

This group of methods includes:

  • __add__(self, other) – called in the summation operator self + other;
  • __sub__(self, other) – called in the subtraction operator self – other;
  • __mul__(self, other) – called in the multiplication operator self * other;
  • __truediv__(self, other) – called in the division operator self / other;
  • __floordiv__(self, other) – called in the statement self // other;
  • __mod__(self, other) – called in the statement self % other;
  • __divmod__(self, other) – called in the statement divmod(self, other);
  • __pow__(self, other [, module]) – called in the statement pow(self, other [, module]);
  • __lshift__(self, other) – called in the left shift operator self << other;
  • __rshift__(self, other) – called in the right shift operator self >> other;
  • __and__(self, other) – called in the statement self & other;
  • __xor__(self, other) – called in the statement self ^ other;
  • __or__(self, other) – called in the statement self | other.

 

3.3.2. Methods for right-hand side operations on binary numbers

In this group of methods, the self argument is placed to the right of the operand. For example, if in a left-hand multiplication operation

self * other

there is a call

self.__mul__(other)

whereas in the right-hand multiplication operation the call

other * self

there is a call

self.__rmul__(other)

The list of right-hand side operations on binary numbers is as follows:

  • __radd__(self, other) – analog of operation __add__(self, other) is only right-handed. This means that the self argument is placed on the right side of the + operator: other + self;
  • __rsub__(self, other) – called in the subtraction operator other-self;
  • __rmul__(self, other) – called in the multiplication operator other * self;
  • __rtruediv__(self, other) – called in the division operator other/self;
  • __rfloordiv__(self, other) – called in the statement other//self;
  • __rmod__(self, other) – called in the statement other % self;
  • __rdivmod__(self, other) – called in the statement divmod(other, self);
  • __rpow__(self, other [, module]) – called in the statement pow(other, self [, module]);
  • __rlshift__(self, other) – called in the left shift operator other << self;
  • __rrshift__(self, other) – called in the right shift operator other >> self;
  • __rand__(self, other) – called in the statement other & self;
  • __rxor__(self, other) – called in the statement other ^ self;
  • __ror__(self, other) – called in the statement other | self.

 

3.3.3. Combined methods for operations on binary numbers

These are methods that are used when overloading operations like +=, -=, >>= and others. The list of these methods is as follows:

  • __iadd__(self, other) – called in the statement +=;
  • __isub__(self, other) – called in the statement -=;
  • __imul__(self, other) – called in the statement *=;
  • __itruediv__(self, other) – called in the division operator /=;
  • __ifloordiv__(self, other) – called in the statement //=;
  • __imod__(self, other) – called in the statement %=;
  • __ipow__(self, other [, modulo]) – called in the statement **=;
  • __ilshift__(self, other) – called in the statement <<=;
  • __irshift__(self, other) – called in the statement >>=;
  • __iand__(self, other) – called in the statement &=;
  • __ixor__(self, other) – called in the statement ^=;
  • __ior__(self, other) – called in the statement |=.

 

3.4. Methods for other operations on numbers

This group of methods includes the following:

  • __neg__(self) – called in the operation -self;
  • __pos__(self) – called in the operation +self;
  • __abs__(self) – called in the operation abs(self);
  • __invert__(self) – called in the operation ~self;
  • __complex__(self) – called in the operation complex(self);
  • __int__(self) – the operation int(self);
  • __float__(self) – the operation float(self);
  • __round__(self) – called in the operation round(self);
  • __index__(self) – called in the operation index(self).

 

3.5. Methods for operations with descriptors

This group of methods is used when an instance of the class (descriptor) in which these methods are defined is assigned to an attribute of the owner class. The list of these methods is as follows:

  • __get__(self, instance, owner) – called to get an attribute from the owner class or an instance of this class;
  • __set __(self, instance, value) – called to set a new value for an attribute in an instance of the owner class;
  • __delete__(self, instance) – called when an attribute needs to be removed on an instance of the owner class.

 

3.6. Methods for operations used with context managers

These methods include methods that implement the context manager protocol. This protocol is used in the with statement. The list of these methods is as follows:

  • __enter__(self) – intended to enter the dynamic context associated with this object;
  • __exit__(self) – implements exit from the dynamic context associated with this object.

 

4. Overloading the class constructor. Example

When an instance is created from a class, then the first method is called the constructor of that class. In this constructor method, it is advisable to write the code for the initial initialization of class data, allocating the necessary resources, and the like. To create a constructor in a class, the __init __() method must be included in that class.

Example code for a class containing the following constructor

class ClassName:
    # a constructor that takes some parameters ...
    def __init__(self, ...):
        # initialization in constructor
        ...
...

After such a class implementation, you can create an instance of the class by calling

obj = ClassName(...) # here ... is a list of parameters that are passed to the constructor

Example.

The Book class is declared, which describes the following data about the book:

  • author – the name of the author;
  • title – name of the book;
  • year – the year of publishing;
  • price – book cost.

The following methods are declared in the Book class:

  • the __init __() method – implements a class constructor that receives 4 parameters;
  • the display() method – displays data about the book in a convenient form;
  • methods for accessing the internal data of the book: getAuthor(), getTitle(), getYear(), getPrice().

After declaring the class, it demonstrates how to instantiate a book using a constructor method.

# Operators overloading in Python.
# Overloading a constructor by implementing the __init __() method in the class
class Book:
    # Метод-конструктор
    def __init__(self, author, title, year, price):
        self.author = author
        self.title = title
        self.year = year
        self.price = price

    # The method that displays data about the book
    def display(self):
        print("author = ", self.author, ", title = ", self.title,
              ", year = ", self.year, ", price = ", self.price)

    # Data access methods in a class
    def getAuthor(self):
        return self.author

    def getTitle(self):
        return self.title

    def getYear(self):
        return self.year

    def getPrice():
        return self.price

# 1. Create the object of class Book,
#   the method-constructor __init__() is called
book1 = Book("Mark Lutz", "Python. ", 2015, 100.01)

# 2. Display book on screen
book1.display()

The result of the program

author = Mark Lutz , title =   Python. , year =   2015 , price = 100.01

 

5. Overloading the + operator for the Point class. Example

If you need to overload the + operator in a class, then in this class you need to implement the __add__() method. The general view of the implementation of the __add__() method is as follows:

class ClassName:
    def __add__(self, value):
        # actions performed by the summation
        # ...
        return result # return the result

After that, you can call the __add __() method as a normal addition operation. For example, if you need to add two instances of the ClassName class, then the code will be something like this

obj1 = ClassName()
obj2 = ClassName()
...
obj3 = obj1 + obj2 # is replaced by obj3 = obj1.__ add__(obj2)
...

Example. The example declares a Point class that implements a point on a coordinate plane. The following methods are implemented in the class:

  • the __init __() method, which overloads the class constructor. The class constructor is called when the class is instantiated;
  • the getXY() method, which returns the value of the coordinate of the point (x, y) as a list;
  • the __add__() method – implements overloading of the addition operator +. The implementation provides for the summation of coordinates along the X and Y axes;
  • the Show() method – displays the coordinates of the point on the screen.

Below is the text of the demo program.

# Operators overloading in Python.
# Overloading operator + (addition).

# The class that contains the __add__() method
class Point:
    # Initialization method - constructor
    def __init__(self, x, y):
        self.x = x
        self.y = y

    # Method that returns (x, y) as a list
    def getXY(self):
        return [ self.x, self.y ]

    # Method that overloads the + operator
    def __add__(self, point):
        self.x = self.x + point.x
        self.y = self.y + point.y
        return self

    # Method that outputs point
    def Show(self, text):
        print(text, " = (", self.x, "; ", self.y, ")")

# Create point 1
pt1 = Point(5, 6)
pt1.Show("pt1")

# Create point 2
pt2 = Point(7, 11)
pt2.Show("pt2")

# Add two points - use operator + overloading
pt3 = pt1 + pt2 # invoke the __add__() method
pt3.Show("pt3 = pt1 + pt2")

After running for execution, the program will give the following result

pt1 = ( 5 ; 6 )
pt2 = ( 7 ; 11 )
pt3 = pt1 + pt2 = ( 12 ; 17 )

 


Related topics