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
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,
--
Miki
http://pythonwise.blogspot.com
There's no such "über-__getattr__", but with some indirection we can
achieve much the same effect:
#Note: Completely untested
from functools import partial
class Whatever(object):
def _getter(self, _name, user, *args, **kwds):
# I assume your actual code will use the *args and **kwds
for auth in self.authorizers:
if not auth.has_user(user):
continue
return getattr(auth, _name)(user)
return ""
def __getattr__(self, name):
if name.startswith("get_"):
return partial(self._getter, _name=name)
else:
raise AttributeError
Cheers,
Chris
--
http://blog.rebertia.com
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)
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"))