
Changing Built-in Behavior using Magic Methods
Magic methods are special methods that you can define to add ‘magic’ to your classes. They are always surrounded by double underscores, for example, the init and str magic methods. Magic methods can enrich our class design by giving us access to Python‘s built-in syntax features.
Python lets our classes inherit from built-in classes. An inheriting child class of a built-in shares all the same attributes, including methods as the built-in. We can take advantage of core built-in functionality, but customize selected operations through the use of magic methods.
In this tutorial, I will tie these two ideas together to showcase how we can inherit from the built-in list class and make use of magic methods in our class design. I will modify the three magic methods which control list indexing. By combining both these features, a class that is very simple to use can be constructed and we can add behavior to methods we desire. Built-in behavior is familiar to all Python developers; in turn, this makes use of our inheriting class easy to learn.
Finally, two further broader examples illustrating how magic methods can be used in broadcast operations and changing an instance’s state will be demonstrated. All accompanying code is available through GitHub.
Example 1: List indexing
Magic methods can be manipulated to modify list indexing. The class MyCustomList, inherits from the built-in list type. This means that any object that is created through the MyCustomList class will behave like a list, except in the places where we choose to selectively customize methods.
getitem, setitem and delitem are magic methods that are invoked when we access the list index. The behavior of these magic methods can be modified.
In the example displayed below, we are discarding the idea of list indexing beginning at the zeroth index. If the user attempts to access an element from our list using the zeroth index, a ValueError exception will be raised and the program will terminate. If the user enters a list index greater than one, the methods will reduce the index by one, and then call the parent class list with the index.
To showcase how these methods defined in the MyCustomList class are used, see below in the Python interactive prompt.

The example shows how getitem, setitem and delitem can be called. Magic methods can be called implicitly. For getitem, to access the first index, simply write the name of the object followed by the index position in square brackets.
What’s most interesting, is that when we ask for the element at index position 1, the integer value 1 is returned, even though 1 is the zeroth element. What we have here is a list which begins it’s indexing starting at 1. In fact, it is making up for the confusion that we have all had when we first learned list indexing.
Now, let’s change the integer value 1 in the list to 100. To do this, we need to invoke setitem. To do this, we simply write the name of the object, followed by square brackets and an assignment. Again, to change the first element in the list we use index position 1. When we output the list again, we can clearly see that the first element has changed from 1 to 100.
Finally, to delete an element from the list delitem can be defined. The delitem magic method is invoked, when we use the del python keyword which resolves to the delitem method call. To further build on our list indexing example, lets delete the first element in the index, the integer value 100. When we call del, followed by the object and the index position of the element we want to delete, in this example, the first element in the list 100, we can now see that 100 has in fact been removed!
Magic methods offer the chance to modify default behavior. Best of all, there is no need to learn new method names or a new interface, so the methods can be intuitively implemented. A guide to using these magic methods implemented in MyCustomList is specified in the table below.


Example 2: The mul magic method
We can also make use of the multiplication operator in our class design. Since we inherit from the built-in list class, we can zip two MyCustomList objects together (because they act like list objects) and iterate through the zip object. During the iterations, we can multiply the elements in each list by its corresponding element in the other list in a broadcast fashion (see mul magic method code snippet below). This broadcast behavior is similar to that found in data analysis packages such as Pandas and Numpy.
The example shows that we can multiple two MyCustomList objects together using the * sign. If we capture the returned value in a variable called list_three, and print list_three, a new list is output. This list is the product of multiplying the elements against each other from the other 2 lists.


The entire source code for the class used in this example, MyCustomList is shown below:
Example Bonus: The call magic method
To finish, I will illustrate how the call magic method in Python can be invoked. __call__
can be particularly useful in classes with instances that need to often change their state. "Calling" the instance can be an intuitive and elegant way to change the object’s state.
Consider the example shown. Here, the class MyClass has an init constructor that expects three arguments passed. These three arguments can be passed in the init method signature and assigned as attributes in the object.
The call magic method is useful when we want to change an instance’s state, without actually creating a new instance.
When the instance is first initialized, I pass in the integers 1, 2 and 3, which are assigned as attributes var_1, var_2, and var_3 in the instance respectively. When I use the print statement to show the output of the instance, obj, by using the dict attribute, I can see that var_1 is assigned the value 1, var_2 is assigned the value 2, and var_3 is assigned the value 3.
Now, let’s propose that I would like to change this instance’s var_1 and var_2 attribute values, whilst keeping the var_3 attribute as it was when the instance was originally constructed.
To do this is simple. I define a call magic method, which permits the var_1 and var_2 attributes to be redefined. Magic methods can be called implicitly, which means I simply call obj(200, 300), and the call method will be invoked. Of course, it is also possible to invoke the call method explicitly, e.g. obj.call(200, 300), but the first method seems more intuitive. Finally, for demonstration purposes, I have printed the instance’s id to definitely show, that we have manipulated the same object.

The call method can be defined in two ways. The arguments can either be passed into the call method signature directly. Alternatively, the *vars argument can be used, which captures all arguments passed and stores them in a tuple, which can be unpacked as shown above.

The source code for this example can be found below.
Summary
Magic methods can enrich our class design by giving us access to core syntax features. In the first examples, we have the best of both worlds. We can inherit from the built-in list class, and modify particular methods in that class to customize behavior. getitem, setitem, and delitem were all modified, but through inheritance, we were still able to make use of the list’s built-in init and repr() methods for example.
We can communicate the use of the objects extremely easily to fellow developers. In the example provided, all we need to tell our fellow developers is that our class acts like a list, just a little differently, here we discard the idea of a zeroth index. There is no need to learn new methods name or a new interface.
In addition, the call magic method was demonstrated. Calling the instance can be an intuitive and elegant way to change the object’s state.