Tuesday, June 19, 2007

Python Inner Classes

Why Python has inner classes at all?
class Outer:
def __init__(self):
self.x = 5

class Inner:
def __init__(self):
self.y = 10

if __name__ == '__main__':
outer = Outer()
inner = outer.Inner()
print outer.x
print inner.y
print inner.x

I've been seeing a pattern where I'd like to be able to create nested class hiearchies like this. Usually it's due to containment. For example, let's say I have a Tools class that can hold a bunch of tool classes like Hammer or Sawsall. Now, I'd like my tool classes to be able to get back at their containing Tools instance. I generally model these classes like this:

class Tools:
def __init__(self):
self.tools = []

def add(tool):
self.tools.append(tool)

class Hammer:
def __init__(self, tools):
self.tools = tools

class Sawsall:
def __init__(self, tools):
self.tools = tools

Okay, so you can see the pattern, right? Each tool class is going to have this tools argument that tells them who their container is. But this doesn't seem right to me. That the tool classes need reference to their container shouldn't have to bother the person using these classes. It seems a bit weird that I would create an Sawsall instance passing a reference to the container I plan to add it to.

tools = Tools()
sawsall = Sawsall(tools)
tools.add(sawsall)

It just looks redundant. Here's how I would like that to read:

tools = Tools
sawsall = tools.Hammer()
tools.add(sawsall)

Now, that's still a little redundant and doesn't seem entirely correct for some reason but I think the container.Class() convention is more clear than the other way. Even without inner classes, we can still get this functionality by adding a Hammer() method to the Tools class:

class Tools:
def Hammer(self):
return Hammer(self)

No comments: