Python meta-magic

I ran into a Python recipe the other day, Generating get/set methods using closures which I found useful for creating data objects from XML. Python's ability to add properties to objects at runtime makes some people cringe, but it was handy for hacking out a utility.
def make_setter(attr, typencv):
    def setter(obj, val):
        obj.__dict__[attr] = typencv(val)
    return setter
make_setter is a function that returns a function that sets an attribute with the same name as attr to the value of the second argument, after applying typecnv. Then I defined a SGMLParser subclass where handle_data is overridden to call self.text_handler. In this example, start_mean sets the handler for the <mean> element to convert to an int:
    def start_mean(self,attrs):
        self.text_handler = make_setter("mean",int)

    def handle_data(self, text):           
        # called for each block of plain text, i.e. outside of any tag and
        # not containing any character or entity references
        # Store the original text verbatim.
        self.pieces.append(text)
        if self.text_handler:
            self.text_handler(self,text)
unknown_starttag provides a default text_handler if an overridden tag hasn't already done it:
    def unknown_starttag(self, tag, attrs):
        if not self.text_handler:
            self.text_handler = make_setter(tag,str)

— Gordon Weakliem at permanent link

Comments

You do the same in Scheme but you just have to do the work at macro-expansion time. It is a bit less pleasant than programming at run-time but not too hard. I once wrote a macro-expansion time HTML tag stripper (it had to run at macro-expansion to interact with PLT's parser tools). Some day I may even document it and release it!

Noel Welsh at

comments are now closed on this post