Operator overloading

Operator overloading was briefly talked about in Chapter 2Data Types and Modules, in the Basic string operations section; now we will see how it works behind the scenes. Operator overloading simply means that objects that you create from classes can respond to actions (operations) that are already defined within Python, such as addition, slicing, printing, and so on. Even though these actions can be implemented through class methods, using overloading ties the behavior closer to Python's object model and the object interfaces are more consistent with Python's built-in objects; hence, overloading is easier to learn and use.

User-made classes can override nearly all of Python's built-in operation methods. These methods are identified by having two underscores before and after the method name, like this: __add__. These methods are automatically called when Python evaluates operators; if a user class overloads the __add__ method, then, when an expression has the + symbol in it, the user's method will be used instead of Python's built-in method.

Continuing with the example from preceding screenshot, next screenshot shows how operator overloading would work in practice:

Creating an overloaded operator

We make a subclass of the Child class on line 55, so it is technically a sub-subclass of the original class, or a grandchild class. GrandChild doesn't override any of Child's methods, so if you wanted, you could put the methods from GrandChild in Child and go from there. However, creating a new subclass allows you flexibility in your program.

When a new instance of GrandChild is made on line 56, the __init__ method takes whatever argument is provided during instance creation and assigns it to the self.data. variable

GrandChild also overrides the + and * operators; when one of these is encountered in an expression, the object on the left of the operator is passed to the self.data argument and the object on the right is passed new_value, as demonstrated on lines 58-61. Note that the Child method of display() is utilized, as it was inherited and not modified.

These custom methods are different from the normal way Python deals with + and *, but these custom methods only apply to instances of GrandChild; other applications of these operators revert to the default Python functionality.

Some items of interest are shown in following screenshot:

Overloading problems

The return statement in the __add__() method creates a new GrandChild instance, with self.data and new_value automatically passed in as arguments. If this wasn't present, then line 59 would error out because instance b wasn't explicitly created, as happens on line 80.

On the other hand, attempting to perform an addition operation directly with instance a causes the memory location of the instance to be displayed (line 77), but the actual value of a never changed (line 78).

The __mul__() method doesn't return an instance, because it simply updates the value of a in-line (line 61). Thus, without the explicit creation of a new instance, attempting to assign a*3 to variable b (line 79) causes the error on line 80, because b is just a regular variable and not an instance of GrandChild.

One final thing to mention about operator overloading is that you can make your custom methods do whatever you want. However, common practice is to follow the structure of the built-in methods. That is, if a built-in method creates a new object when called, your overriding method should too. This reduces confusion when other people are using your code. Regarding the preceding example, the built-in method for resolving * expressions creates a new object (just as the + method does); therefore, the overriding method we created should probably create a new object too, rather than changing the value in-place as it currently does. You're not obligated to "follow the rules" but it does make life easier when things work as expected.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.26.221