Mangle function name with decorator?

J. Cliff Dyer jcd at sdf.lonestar.org
Wed Mar 25 16:28:09 EDT 2009


On Wed, 2009-03-18 at 08:18 -0700, Adam wrote:
> On Mar 18, 10:33 am, "J. Cliff Dyer" <j... at sdf.lonestar.org> wrote:
> > You might be interested in redefining __getattribute__(self, attr) on
> > your class.  This could operate in conjunction with the hash tables
> > (dictionaries) mentioned by andrew cooke.  i.e. (untested code):
> >
> > class C(object):
> >     def __init__(self):
> >         self._get_table = {}
> >         self._post_table = {}
> >
> >     def __getattribute__(self, x):
> >         if self.method=='GET':
> >             return object.__getattribute__(self, _get_table)[x]
> >         elif self.method=='POST':
> >             return object.__getattribute__(self, _post_table)[x]
> >         else:
> >             raise AttributeError
> >     @GET
> >     def foo(x):
> >         return "Got", x
> >     @POST
> >     def foo(x)
> >         return "Posted to", x
> >
> > This is definitely not functional code, but might get you in the right
> > direction on __getattribute__.  __getattr__ might also work for you.  I
> > haven't worked too much with these corners of python.
> >
> > Cheers,
> > Cliff
> 
> Hey, Cliff.  Thanks for sharing this idea.  Unfortunately, providing a
> way to actually call the method with the mangled name is relatively
> easy, and there are options there.  The real issue, to me, seems to be
> finding a way to prevent Python from eating all but the last version
> of a function definition in a class.  While decorators are a elegant
> and unintrusive approach, I don't believe that there is any way for a
> decorator to collection information in a data structure and then
> provide that data back to the class instance or the class's metaclass.
> 

If your __getattribute__ dispatches method calls from a dictionary, it
shouldn't matter if the original name of the method has been blown away.
The actual method object lives on, and is accessed normally from the
user's standpoint.

I'm just thinking out loud now on ideas I haven't tested myself, but
what if your decorator were itself a method of the same class, so you
had something like this:

class BarBar(object):
    def decorate_get(self, func):
        pass
    def decorate_post(self, func):
        pass

    @self.decorate_get
    def foo(self):
        pass
    @self.decorate_post
    def foo(self):
        pass

Then the decorator has access to self, and can pass around whatever
information it needs.  Maybe the decoration methods should live on a
base class somewhere.

class Decoratable(object):
    def get(self, func):
        pass
    def post(self, func):
        pass

class BarBar(Decoratable):
    @self.get
    def foo(self):
        pass
    @self.post
    def foo(self)
        pass

> I'm beginning to think that I am trying to get the square peg of
> Python to fit into the round hole of a .NET idiom.  

Well, square is just one abstraction layer away from round anyway,
right?

> I am trying to
> borrow what I think is a really elegant and useful idiom from ASP.NET
> MVC.  Specifically, in an ASP.NET MVC Controller class, I can have two
> methods with the same name that are called for different HTTP Verbs by
> applying an Attribute:
> 
>         public ActionResult Payment() {
>             ViewData["Title"] = "Payment Information";
>             ViewData["submit_text"] = "Next >";
> 
>             return View();
>         }
> 
>         [AcceptVerbs(HttpVerbs.Post)]
>         public ActionResult Payment(FormCollection form) {
> 
>             return RedirectToAction("Legal");
>         }
> 
> Right?  The first Payment method is called when the Payment page is
> rendered.  The second is called when the form that it contains is
> submitted.  I find it to be readable, elegant and it does not intrude
> into the actual logic of the method itself.  The alternatives that I
> can readily identify are less-than-optimal.  For instance, if could
> just have an if statement inside the body of the method that branches
> on the HTTP verb:
> 
> def Payment(self):
>     if self.request.verb == 'GET':
>         # Do stuff for GET
>     elif self.request.verb == 'POST':
>         # So stuff for POST
> 
> Yes, it would work, but it is ugly and requires me to mix in the same
> function the behaviors for two very separate things.
> 
> Or, I could do something like this:
> 
> def GET_Payment(self):
>     # Do stuff for GET
> 
> def POST_Payment(self):
>     # Do stuff for POST
> 
> This is trivially-easy to implement (in this case, a metaclass can
> very easily manipulate the namespace), but it makes the source code
> less appealing and just feels crufty and hacky.  It also makes it
> difficult to deal elegantly with having one method respond to more
> than verb like I could if I could write:
> 
> @GET
> @POST
> def foo(self):
>     # Do stuff for page foo, if it is GET or POST; PUT and DELETE not
> allowed!
> 
> 
> --
> http://mail.python.org/mailman/listinfo/python-list
> 




More information about the Python-list mailing list