Wednesday, April 26, 2006

How to work with Metaclasses

I just released another version of pywinauto - and I am quite happy with it. I even squeezed some more performance improvements (it is now approximately 10-20% faster then the previous release - though I think it will be waiting for the application itself to respond most of the time!).

One thing that I had wanted to make into this release was a change from using a function to return the correct control Wrapper class, to having a __metaclass__ attribute in the base class, and add functionality to it's __new__ method.

something like: (paraphrased - not run!)

class MetaWrapper(type):
registry = {}

# this is called when each class is defined
def __init__(cls, name, bases, attrs):
# add information defined in cls to the registry
# so that later we can return the correct class

def GetWrapper(handle):
# look in registry for correct class
return correct_class
GetWrapper = staticmethod(GetWrapper)

class HwndWrapper(object):
__metaclass__ = MetaWrapper

# called before each instance is created
def __new__(cls, handle):
correct_class = cls.GetWrapper(handle)

# need to call base __new__ ?
obj = correct_class.__new__(correct_class)

# as we are returning a different class from HwndWrapper we need to
# initialize it
return obj

def __init__(self, handle):
# rest of stuff here

But I was getting errors I could not explain! Now that I write that out - there were times when I was returning a HwndWrapper instance, would that mean that it was getting initialized twice? I don't think that would have caused the problems I was seeing (but then again - I can't think of anything else either!)

Maybe one of you out there who knows this magic better can set me on the right track. Is this even something that I should be using - or are meta classes too much magic most of the time?

Anyway - happy pythoneering :-)