Tuesday, February 10, 2009

The best way to call Python methods

What is the best way to invoke behaviour on objects in Python? Is there any better way than simply invoking a method which defines behaviour for a given instance? Or, given a class method, does the same principle not apply?

I would say it depends how you are using the instances or the classes. In the majority of cases, an instance is created, and some behaviour is invoked from that instance. However, the invoking code doesn't always know what behaviour is supported by the instance. For instance, consider the following example.
#Example; testing is a method is callable.

class MyClass:
def do_something(self):
print 'Doing something...'

def do_something(obj):
if hasattr(obj, 'do_something') and callable(obj.do_something):
obj.do_something()

if __name__=="__main__":
do_something(MyClass())

Here, we have a simple class, MyClass, that will "do something". We also have a function that will "do something". The purpose of the do_something() function is to accept some object as a parameter and invoke the "do something" behaviour on that object.

The problem I'm interested in here is that the do_something() function has no way of knowing for sure that it will be able to "do something" with the provided instance. It is the responsibility of the do_something() function to determine the invoking capability of the instance.

Now, what if we take the responsibility of know the invoking capabilities of the instance away from the do_something() function and gave it to the MyClass class? For example.
#Example; testing is a method is callable.

class MyClass:
def _do_something(self):
print 'Doing something...'
do_something=property(_do_something)

def do_something(obj):
try:
obj.do_something
except AttributeError:
pass

if __name__=="__main__":
do_something(MyClass())

In this example, obj.do_something is a managed attribute instead of a method. The do_something() function no longer needs to test the invoking capabilities of the provided instance. However, more responsibility has been added to MyClass.

Which solution is better? It depends. If our system were simple and we only needed managed attributes for all instances passed to do_something(), the latter approach may simplify things. I think in the majority of cases, the first approach offers more flexibility.