我有一个类的工作是包装另一个类(我无法控制的代码),拦截对包装类的所有调用,执行一些逻辑,并将调用传递给底层类。这是一个例子:
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()
正如您所看到的,我这样做的方法是在包装类上实现__getattr__
并委托给底层类。这种方法的缺点是LoggingGithubRepositoryWrapper
的用户不知道底层GithubRepository
实际上具有哪些属性/方法。
这引出了我的问题:有没有办法定义或记录__getattr__
处理的调用?理想情况下,我希望能够在{{1}上自动完成并提供支持的方法列表。感谢您的帮助!
答案 0 :(得分:1)
您可以通过几种不同的方式执行此操作,但它们不会涉及使用__getattr__
。
您真正需要做的是动态创建您的类,或者至少在您的类上动态创建包装函数。在python中有几种方法可以做到这一点。
您可以使用type()
或元类构建类定义,或使用__new__
方法在类实例化上构建它。
每次拨打LoggingGithubRepositoryWrapper()
时,都会调用__new__
方法。在这里,它查看github_repository
参数的所有属性,并查找所有非私有方法。然后,它在实例化的LoggingGithubRepositoryWrapper
类实例上创建一个函数,该实例在日志语句中包装repo调用。
最后,它传回修改后的类实例。然后调用__init__
。
from types import MethodType
class LoggingGithubRepositoryWrapper(object):
def __new__(cls, github_repository):
self = super(LoggingGithubRepositoryWrapper, cls).__new__(cls)
for 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):
... # this is all the same