views:

158

answers:

3

Goal: Make it possible to decorate class methods. When a class method gets decorated, it gets stored in a dictionary so that other class methods can reference it by a string name.

Motivation: I want to implement the equivalent of ASP.Net's WebMethods. I am building this on top of google app engine, but that does not affect the point of difficulty that I am having.

How it Would look if it worked:

class UsefulClass(WebmethodBaseClass):
    def someMethod(self, blah):
        print(blah)

    @webmethod
    def webby(self, blah):
        print(blah)

# the implementation of this class could be completely different, it does not matter
# the only important thing is having access to the web methods defined in sub classes
class WebmethodBaseClass():
    def post(self, methodName):
        webmethods[methodName]("kapow")

    ...    

a = UsefulClass()
a.post("someMethod") # should error
a.post("webby")  # prints "kapow"

There could be other ways to go about this. I am very open to suggestions

+4  A: 

This is unnecessary. Just use getattr:

class WebmethodBaseClass():
    def post(self, methodName):
        getattr(self, methodName)("kapow")

The only caveat is that you have to make sure that only methods intended for use as webmethods can be used thus. The simplest solution, IMO, is to adopt the convention that non-webmethods start with an underscore and have the post method refuse to service such names.

If you really want to use decorators, try this:

def webmethod(f):
    f.is_webmethod = True
    return f

and get post to check for the existence of the is_webmethod attribute before calling the method.

Marcelo Cantos
+1  A: 

This would seem to be the simplest approach to meet your specs as stated:

webmethods = {}

def webmethod(f):
    webmethods[f.__name__] = f
    return f

and, in WebmethodBaseClass,

def post(self, methodName):
    webmethods[methodName](self, "kapow")

I suspect you want something different (e.g., separate namespaces for different subclasses vs a single global webmethods dictionary...?), but it's hard to guess without more info exactly how your desires differ from your specs -- so maybe you can tell us how this simplistic approach fails to achieve some of your desiderata, so it can be enriched according to what you actually want.

Alex Martelli
A: 
class UsefulClass(WebmethodBaseClass):

    def someMethod(self, blah):
        print(blah)

    @webmethod
    def webby(self, blah):
        print(blah)

class WebmethodBaseClass():
    def post(self, methodName):
        method = getattr(self, methodName)
        if method.webmethod:
            method("kapow")

    ...

def webmethod(f):
    f.webmethod = True
    return f

a = UsefulClass()
a.post("someMethod") # should error
a.post("webby")  # prints "kapow"
Trey