更新:我找到了一个问题的答案:
如果没有从__getattr__
生成递归调用,我怎么能做我认为的'动态复合委托'?
此时我对功能感到满意。我只希望我能找到一个不需要__getattr__
装饰器的解决方案。装饰器对于调试是有问题的,并且创建只能应用于一个方法(__geattr__
)的装饰器似乎不是Pythonic。
通过向您的班级添加__getattr__
和装饰器来使用动态委派:
class Story():
@delegate(delegate_to='chapter book',
only_delegate='title')
def __getattr__(self, attr_name):
raise AttributeError("'%s' object has no attribute '%s'" %
(self.__class__.__name__,attr_name))
它的工作原理如下:
class Other():
""" Placeholder for Chapter and Book classes """
my_story = Story()
chp1 = Other()
my_story.chapter = chp1
bk = Other()
my_story.book = bk
#delegation, with 'chapter' having precedence over 'book'
bk.title = "Title from book"
chp1.title = "Title from chapter"
assert my_story.title == "Title from chapter"
del chp1.title
assert my_story.title == "Title from book"
#local override
my_story.title = "Title from story"
assert my_story.title == "Title from story"
delegate()
的代码是:
def delegate(delegate_to:str, only_delegate:str=''):
#split into lists at decoration time so we don't have split each time
#an attribute is delegated
delegate_to = delegate_to.split()
only_delegate = only_delegate.split()
def ga_decorator(fn):
#the decorator can only be applied to getattr, not Pythonic :-(
if fn.__name__ != '__getattr__' and fn.__name__ != 'ga_decorated':
raise AttributeError("Delegation can only apply to '__getattr__'")
def ga_decorated(self, attr_name):
#To enable delegation on any attribute, set only_delegate=''
if not only_delegate or (attr_name in only_delegate):
#delegate_to is a list of members of 'self' that reference
#the objects we will delegate to.
for m in delegate_to:
if m in dir(self):
member = getattr(self, m)
if attr_name in dir(member):
return getattr(member, attr_name)
return fn(self, attr_name)
return ga_decorated
return ga_decorator
only_delegate
列表可以包含方法和委托以相同的方式工作。
如果要将一个属性委托给一组对象,将其他属性委托给另一组对象,请在更多委托语句上进行堆栈:
class Story():
@delegate(delegate_to='collection',
only_delegate='archivist')
@delegate(delegate_to='chapter book',
only_delegate='title author')
def __getattr__(self, attr_name):
raise AttributeError("'%s' object has no attribute '%s'" %
(self.__class__.__name__,attr_name))
答案 0 :(得分:0)
避免在__getattr__
中创建递归__getattr__
来电的一种方法是替换
hasattr(obj, attr_name)
与
attr_name in dir(obj)
在装饰者中,这个:
for m in delegate_to.split():
#why does this cause recursion?
if hasattr(self, m):
member = getattr(self, m)
if hasattr(member, attr_name):
return getattr(member, attr_name)
变为
for m in delegate_to.split():
if m in dir(self):
member = getattr(self, m)
if attr_name in dir(member):
return getattr(member, attr_name)
根据我的测试结果,dir()
似乎无法间接拨打getattr
。