python - What's the proper way of defining or documenting calls handled by __getattr__? -
i have class who's job wrap class (code don't control), intercept calls wrapped class, perform logic, , pass along call underlying class. here's example:
class githubrepository(object): def get_commit(self, sha): return 'commit {}'.format(sha) def get_contributors(self): return ['bobbytables'] class logginggithubrepositorywrapper(object): def __init__(self, github_repository): self._github_repository = github_repository def __getattr__(self, name): base_func = getattr(self._github_repository, name) def log_wrap(*args, **kwargs): print "calling {}".format(name) return base_func(*args, **kwargs) return log_wrap if __name__ == '__main__': git_client = logginggithubrepositorywrapper(githubrepository()) print git_client.get_commit('abcdef1245') print git_client.get_contributors() as can see, way implementing __getattr__ on wrapping class , delegating underlying class. downside approach users of logginggithubrepositorywrapper don't know attributes/methods underlying githubrepository has.
this leads me question: is there way define or document calls handled __getattr__? ideally, i'd able autocomplete on git_client. , provided list of supported methods. in advance!
you can few different ways, wont involve use of __getattr__.
what need dynamically create class, or @ least dynamically create wrapped functions on class. there few ways in python.
you build class definition using type() or metaclasses, or build on class instantiation using __new__ method.
every time call logginggithubrepositorywrapper(), __new__ method called. here, looks @ attributes on github_repository argument , finds non-private methods. creates function on instantiated logginggithubrepositorywrapper class instance wraps repo call in logging statement.
at end, passes modified class instance. __init__ called.
from types import methodtype class logginggithubrepositorywrapper(object): def __new__(cls, github_repository): self = super(logginggithubrepositorywrapper, cls).__new__(cls) name in dir(github_repository): if name.startswith('__'): continue func = getattr(github_repository, name) if isinstance(func, methodtype): setattr(self, name, cls.log_wrap(func)) return self @staticmethod def log_wrap(func): def wrap(*args, **kwargs): print 'calling {0}'.format(func.__name__) return func(*args, **kwargs) return wrap def __init__(self, github_repository): ... # same
Comments
Post a Comment