Monday, November 16, 2009

Calling All Objects

Python, being the object-oriented language that it is, provides developers with the ability to override the default behavior of classes. This includes the default operator behavior, or, operator-overloading. This is done in Python like operator-overriding. The default operator functionality for each operator has a corresponding method that may be overridden. I like this a lot as it isn't a big deal to completely change the face of a class in a couple hours should the need arise.

One of the more interesting ways one can customize the default class behavior provided by the language is to make instances of classes callable. An example of a callable object would be a function or a method. It is callable because it is a parametrized piece of behavior that can be invoked. The invoking context then supplies parameter values to this callable behavior.

Shown below is an example of how the __call__() method can be overridden to make instances callable.
#Example; Using __call__ to set attributes.

#Simple person class.
class Person(object):

#Constructor. Initialize attributes.
def __init__(self, first_name=None, last_name=None):
self.first_name=first_name
self.last_name=last_name

#Make Person instances callable. Set the provided
#attributes and return the modified instance.
def __call__(self, *args, **kw):
for attr in kw.keys():
setattr(self, attr, kw[attr])
return self

#Return a formatted string with the attribute values.
def format(self):
return "First Name: %s\nLast Name: %s"%\
(self.first_name, self.last_name)

#Main.
if __name__=="__main__":

#Construct a Person instance with initial attribute values.
print "Constructing..."
person_obj=Person(first_name="Joe", last_name="Blow")

#Display output.
print person_obj.format()

#Call the person object to fetch a modified version.
print "Updating..."
print person_obj(first_name="John", last_name="Smith").format()

Here, we have a simple Person class. This class defines a constructor that will set the two attributes of the class. The __call__() method will take any supplied keyword parameters and set them as attributes of the instance. The key aspect of this __call__() implementation to note is the fact that the instance itself is returned by the function. It is by doing this that we allow the state of the instance to be updated and retrieve the altered version of the instance in the same invocation. This is similar to having a setter type function return the instance. I like the callable instance approach simple because the concept is more prevalent in the code.