Like __getattr__ but with args and kwargs as well

Peter Otten __peter__ at web.de
Fri May 28 13:52:08 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?

Yes, and for the above example it is easier to implement than you think:

class MA(object):
    def __init__(self, authorizers):
        self.authorizers = authorizers
    def __getattr__(self, name):
        def get(self, user):
            for auth in self.authorizers:
                if auth.has_user(user):
                    return getattr(auth, name)(user)
        return get.__get__(self)

You can modify it to pass along arbitrary keyword arguments:

class MA(object):
    def __init__(self, authorizers):
        self.authorizers = authorizers
    def __getattr__(self, name):
        def get(self, **kw):
            for auth in self.authorizers:
                if auth.has_user(kw["user"]):
                    return getattr(auth, name)(**kw)
        return get.__get__(self)

Peter



More information about the Python-list mailing list