Like __getattr__ but with args and kwargs as well

G

Giampaolo Rodolà

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?


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

Miki

class MixedAuthorizer:
def __init__(self, *args):
# expected a list of class instances
self.authorizers = args
self._set_methods()

def _set_methods(self):
for attr in ("home", "password"):
def fn(user):
return self._get_attr(user, attr)
setattr(self, "get_%s" % attr, fn)

def _get_attr(self, user, attr):
auths = [auth for auth in self.authorizers if
auth.has_user(user)]
if not auths:
return ""

method_name = "get_%s" % attr
method = getattr(auths[0], method_name, None)
if not fn:
raise ValueError("Unknown attribute - %s" % method_name)

return fn(user)

HTH,
 
M

Miki

        method = getattr(auths[0], method_name, None)
Should be
fn = getattr(auths[0], method_name, None)
 
P

Peter Otten

Giampaolo said:
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
 
G

Giampaolo Rodolà

2010/5/28 Peter Otten said:
Giampaolo said:
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



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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,077
Latest member
SangMoor21

Latest Threads

Top