While an explicit logging call (or logging decorator, as warwaruk suggests) is the most straightforward approach, it is possible to automate logging, if you're willing to play a naming trick such as having the logical foo method be implemented by Foo. Python is case-sensitive, so those are separate and distinct. Then implement a __getattr__ method, like so:
class AutoLogger(object):
def __getattr__(self, attr):
try:
return self.__class__.__dict__[attr]
except KeyError:
func = self.__class__.__dict__[attr.capitalize()]
return lambda *args, **kwargs: self.log_call(attr, func, *args, **kwargs)
def log_call(self, func_name, func, *args, **kwargs):
func(self, *args, **kwargs)
print func_name, 'has been called (handled by', func_name.capitalize() + ')'
class BigAutoLoggerClass(AutoLogger):
def Foo(self):
print 'calling Foo'
b = BigAutoLoggerClass()
b.Foo()
print "---"
b.foo()
This yields:
calling Foo
---
calling Foo
foo has been called (handled by Foo)
bar would similarly be implemented by Bar, and so on.
If you don't like this naming slight-of-hand, logging can also be automated via the sys.settrace() function. That, however, adds a lot of run-time overhead and is really only suited for debugging or situations where low(ish) performance is okay.