Underscore Methods in Python

Anyone who has started object-oriented programming in Python would have come across functions that look like “__<func_name>__(self)”. These are called underscore methods or indirect functions. SO let’s learn about Underscore methods in Python.

This post deals with some of these methods and their usage in classes and objects.

Prerequisites: Classes and Objects in Python (refer to this)

What are Underscore Methods in Python

Underscore methods are often also referred to as “magic” or special methods. They are simply class methods that are not meant to be called explicitly (although they can be) but are invoked under specific circumstances. The usage of operators, for instance, invokes underscore method of that particular object for the operator used. These operator functions are often used in Operator Overloading. They also pass arguments(if any) by themselves.

These methods are already present in the user namespace and can be re-defined inside the classes, as per the user’s needs. Let us take a look at a few common ones.

Common Underscore Methods in Python

We define a class and keep adding these underscore methods one after the other to¬† see how they work. We’ll print the output finally for all the functions together!

__init__(self)

This is the constructor function for python classes. It is automatically invoked when an object of the class if getting created. This is similar to constructors in any programming language. It has to be given the self keyword, like all other member functions and can be given other arguments as well.

Consider the following program,

class Sample:
    ctr = 0   #Class Variable to count number of objects present
    def __init__(self):
        print "Object Initialized"
        Sample.ctr += 1
        self.data = 0
        self.other = "Nothing"

__str__(self)

This is a commonly used method in a lot of classes. It is called when an object of this class is tried and converted to a string. Hence, it is also invoked when the object is printed. That is because the print statement converts any object into a string before printing it. A return value has to be defined for the function, which should essentially be a string. Whenever the string conversion of the object is done, this return value is used. The general purpose of this function is to return asl details of the class in a readable string format

Let’s add this to our class,

#Added as a member function of the class

def __str__(self):
    ret = str(self.data)+" "+self.other
    return ret

__repr__(self)

This has literally the same format and invocations as the __str__ method. However, the programmer is expected to use them differently. __str__ is used to return an informal data about its object. That means that this data should be readable and is generally meant to be shown to an end-user. ON the other hand, __repr__ is used to return formal data about the object. The kind of data that can be used within the program for various implementation purposes. The best way to understand it would be to look at how python has used it for its built-in data-types

Underscore Methods in Python

repr() has returned a string containing the string object. That is a string of a string. Whereas, str() has returned the string itself. The former can be used within the program, for instance, with the eval()n function for some other operations. The latter can be used to display to the end-user.

Note that, when the print statement is used with an object, first the __str__ function is invoked. If it has not been defined, __repr__ is invoked.

Usage in the class,

def __repr__(self):
    print "__repr__ function"
    ret = "data holds %d, other holds '%s'" %(self.data,self.other)
    return ret

__nonzero__(self)

The interpreter invokes this function whenever an object of this class is used in a truth testing statement or the bool() function is used along with it. The recommended return values are True, False, 0 or 1. If this is not defined, the __len__ function is invoked. If that is also not defined, the truth testing results in True by default for instances of a class.

def __nonzero__(self):
    if self.data==0:
        return False
    else:
        return True

__len__(self)

The interpreter invokes the __len__ function whenever the object of this class is used with len() function or in the truth expressions as per the case mentioned above. The recommended integer return value is the size or number of data members in the object.

def __len__(self):
    ret = len(str(self.data))+len(self.other)
    return ret

__call__(self)

The function is invoked when the object is called like a function, with or without function depending on the definition of this function. If the function is not present, it throws an error saying, “object not callable”.

def __call__(self):
    print "Object Has Been Called"

__abs__(self)

This function is invoked when the abs() function is used with the class’ object. If this function is not defined, an AttributError is thrown by the interpreter.

def __abs__(self):
    if self.data>=0:
        return self.data
    else:
        return -self.data

__del__(self)

This is the destructor function for python classes. It is invoked just before an object goes out of scope and is going to be removed out of the memory. Final method invocations and data changes can be made in this function, that is intended to happen just before the destruction of an object.

Usage in the class,

def __del__(self):
    print "Object being Destroyed"
    Sample.ctr += 1

Example Python Program to show underscore methods in Python

The following is the complete class definition with all the above function definitions. Each function is executed suitably as well.

class Sample:
    ctr = 0   #Class Variable to count number of objects present
    def __init__(self):
        print "Object Initialized"
        Sample.ctr += 1
        self.data = 0
        self.other = "Nothing"
    def __str__(self):
        ret = str(self.data)+" "+self.other
        return ret
    def __repr__(self):
        ret = "data holds %d, other holds '%s'" %(self.data,self.other)
        return ret
    def __nonzero__(self):
        if self.data==0:
            return False
        else:
            return True
    def __len__(self):
        ret = len(str(self.data))+len(self.other)
        return ret
    def __call__(self):
        print "Object Has Been Called"
    def __abs__(self):
        if self.data>=0:
            return self.data
        else:
            return -self.data
    def __del__(self):
        print "Object being Destroyed"
        Sample.ctr += 1

obj = Sample()        
print obj
print repr(obj)
print bool(obj)
print len(obj)
obj()
print abs(obj)
del obj

And the output,

underscore in Python

Some more functions

There are several other such underscore function that is invoked with their attached functions and operations. A list with a brief description of all such functions can be found on the Python documentation page

There is a whole range of such functions for managing objects when they are used with various operators. This is called operator overloading. Use this for a detailed explanation on that.

Feel free to leave behind any sort of feedback, suggestions, doubts below.

Leave a Reply

Your email address will not be published. Required fields are marked *