[FRPythoneers] Method trickery

Eric Brunson brunson at level3.net
Mon Oct 22 23:19:32 MDT 2001


I've got a problem that I've decided to solve through brute force, but
I spent quite a while trying to find the feature I wanted and now I'm
just on a mission.

Here's the situation:

When I first started using python I wrote a very straight forward
class for html generation that mimicked the behavior of the perl
CGI.pm module.  Most of the methods of this class take a dict as the
first argument and in all but a few cases, simply drop the key/value
pairs into the html as text, e.g:

Html.textfield( { 'name': 'myfield', 'width': 12, 'value': 'bob' } )

simply returns the string:

<INPUT width="12"  TYPE="text"  name="myfield"  value="bob" >

Some methods take additional arguements, but by convention they all
expect a dict as the first parameter.


A while back, after learning more about python, I rewrote the class so
that it accepted a variable named parameter list so the above would
now be called: 

Html.textfield( name='myfield', width=12, value='bob' )

which I just like much more.

The problem came when I started modifying all my code to use the new
calling conventions, there was just too much of it for me to justify
the time it was taking to convert over.  Remember that many of the
methods take additional arguments and named parameter have to be after
all positional arguments.

Be that as it may, whether I'm just lazy or whatever, it occurred to
me that there might be a mechanism similar to the __getitem__ or
__getattr__ methods that I could use to intercept any method call and
use the dict passed in to call the new code with the new conventions.

Here's a kind of meta-python version of what I thought it'd look like:

class Html( newHtml ):
    def __methodcalled__( self, methodname, *args ):
	funcptr = getattr( self, methodname ) 
	if type( args[0] ) is type( {} ):
	    return apply( funcptr, args[1:], args[0] )
	else:
	    return apply( funcptr, args )


That be the entire amount of coding I would have to do to implement
the sort of backwards compatability I want, but there is no
__methodcall__ method of a class (you can see how it could be easy to
get into an infinite recursion).

I thought I had it sussed earlier with __getattr__, but when I
actually started writing the code, I realized I could intercept the
lookup of the method, but not the call.

I also started reading about the "Don Beaudry hook" in "Metaclasses in
Python 1.5" ( http://www.python.org/doc/essays/metaclasses ), but I
think I'm going to have to read that a few dozen more times before I
understand it well enough to know if that's the solution.

So, any thoughts on a clever solution?

e.

BTW, I've actually written a wrapper for every method in newHtml that
would need its arguments munged from the old calling conventions, so
this isn't a solution to that problem, it's more of an academic
exercise that has caught my fancy and I'd like figure out for future
reference.


-- 
 Eric Brunson   brunson at level3.net   page-eric at level3.net  
tcA thgirypoC muinelliM latigiD eht detaloiv tsuj evah uoY



More information about the FRPythoneers mailing list