Like __getattr__ but with args and kwargs as well

Giampaolo Rodolà g.rodola at gmail.com
Fri May 28 14:29:51 EDT 2010


2010/5/28 Peter Otten <__peter__ at web.de>:
> 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
> --
> http://mail.python.org/mailman/listinfo/python-list
>



Thanks, this has been helpful.
I managed to write this monster: =)


class MixedAuthorizer(object):

    def __init__(self, *authorizers):
        self.authorizers = authorizers

    def __getattr__(self, name):

        def get(self, user, *args, **kwargs):
            for auth in self.authorizers:
                if auth.has_user(user):
                    method = getattr(auth, name)
                    return method(user, *args, **kwargs)

            # if we reached this point no user was found
            if name == "validate_authentication":
                return False
            if name.startswith("get"):
                return ""
            if name.startswith("has"):
                return False

        return get.__get__(self)


--- Giampaolo
http://code.google.com/p/pyftpdlib
http://code.google.com/p/psutil



More information about the Python-list mailing list