Like __getattr__ but with args and kwargs as well

MRAB python at mrabarnett.plus.com
Fri May 28 14:42:45 EDT 2010


Giampaolo Rodolà wrote:
> I know, the title doesn't say much, but I had no better ideas. =)
> I have a class within a serie of redundant methods, which looks like this:
> 
> class MixedAuthorizer:
> 
>     def __init__(self, *args):
>         # expected a list of class instances
>         self.authorizers = args
> 
>     def get_home(self, user):
>         for auth in self.authorizers:
>             if not auth.has_user(user):
>                 continue
>             return auth.get_home(user)
>         return ""
> 
>     def get_password(self, user):
>         for auth in self.authorizers:
>             if not auth.has_user(user):
>                 continue
>             return auth.get_password(user)
>         return ""
> 
>      # follows a long list of get_* methods as above
>      ...
> 
> 
> Considering that I always do the same thing (iterate over a list of
> objects -> call obj.has_user() -> call obj.get_*()) I would like to
> know if there's a more compact way to do that.
> What I basically need is something like __getattr__ but which provides
> the arguments and eventually the keyword arguments a method has been
> called with, other than just its name.
> Actually I'm not even sure whether Python can reach such a level of
> dynamism but I wanted to give it a try anyway.
> Is there a way to do such a thing?
> 
Here's a way (mis)using a decorator (written in Python 3):

def locate(func):
     def lookup(self, user):
         for auth in self.authorizers:
             if auth.has_user(user):
                 return getattr(auth, func.__name__)()
         return ""
     return lookup

class Authorizer:
     def __init__(self, user):
         self.user = user
     def has_user(self, user):
         return self.user == user
     def get_home(self):
         return "{}-HOME".format(self.user)
     def get_password(self):
         return "{}-PASSWORD".format(self.user)

class MixedAuthorizer:
     def __init__(self, *authorizers):
         self.authorizers = authorizers
     # The following methods are used only as placeholders.
     @locate
     def get_home(self): pass
     @locate
     def get_password(self): pass

a1 = Authorizer("USER1")
a2 = Authorizer("USER2")
m = MixedAuthorizer(a1, a2)
print(m.get_home("USER1"))
print(m.get_password("USER2"))




More information about the Python-list mailing list