看看下面的代码:
class A(object):
defaults = {'a': 1}
def __getattr__(self, name):
print('A.__getattr__')
return self.get_default(name)
@classmethod
def get_default(cls, name):
# some debug output
print('A.get_default({}) - {}'.format(name, cls))
try:
print(super(cls, cls).defaults) # as expected
except AttributeError: #except for the base object class, of course
pass
# the actual function body
try:
return cls.defaults[name]
except KeyError:
return super(cls, cls).get_default(name) # infinite recursion
#return cls.__mro__[1].get_default(name) # this works, though
class B(A):
defaults = {'b': 2}
class C(B):
defaults = {'c': 3}
c = C()
print('c.a =', c.a)
我有一个类层次结构,每个类都有自己的字典,其中包含一些默认值。如果类的实例没有特定属性,则应返回它的默认值。defaults
如果当前类的字典中不包含该属性的默认值,defaults
则应搜索超类的字典。
我正在尝试使用递归类方法来实现这一点get_default
。不幸的是,程序陷入了无限递归。我的理解super()
显然不足。通过访问__mro__
,我可以让它正常工作,但我不确定这是一个正确的解决方案。
我感觉答案就在这篇文章的某处,但我还没有找到。也许我需要求助于使用元类?
编辑:在我的应用程序中,__getattr__
首先检查self.base
. 如果不是None
,则需要从那里获取属性。只有在其他情况下,必须返回默认值。我可能会覆盖__getattribute__
. 那会是更好的解决方案吗?
编辑 2:下面是我正在寻找的功能的扩展示例。它目前是使用__mro__
(unutbu 早期的建议,而不是我原来的递归方法)实现的。除非有人可以提出更优雅的解决方案,否则我很乐意使用此实现。我希望这能解决问题。
class A(object):
defaults = {'a': 1}
def __init__(self, name, base=None):
self.name = name
self.base = base
def __repr__(self):
return self.name
def __getattr__(self, name):
print(" '{}' attribute not present in '{}'".format(name, self))
if self.base is not None:
print(" getting '{}' from base ({})".format(name, self.base))
return getattr(self.base, name)
else:
print(" base = None; returning default value")
return self.get_default(name)
def get_default(self, name):
for cls in self.__class__.__mro__:
try:
return cls.defaults[name]
except KeyError:
pass
raise KeyError
class B(A):
defaults = {'b': 2}
class C(B):
defaults = {'c': 3}
c1 = C('c1')
c1.b = 55
print('c1.a = ...'); print(' ...', c1.a) # 1
print(); print('c1.b = ...'); print(' ...', c1.b) # 55
print(); print('c1.c = ...'); print(' ...', c1.c) # 3
c2 = C('c2', base=c1)
c2.c = 99
print(); print('c2.a = ...'); print(' ...', c2.a) # 1
print(); print('c2.b = ...'); print(' ...', c2.b) # 55
print(); print('c2.c = ...'); print(' ...', c2.c) # 99
输出:
c1.a = ...
'a' attribute not present in 'c1'
base = None; returning default value
... 1
c1.b = ...
... 55
c1.c = ...
'c' attribute not present in 'c1'
base = None; returning default value
... 3
c2.a = ...
'a' attribute not present in 'c2'
getting 'a' from base (c1)
'a' attribute not present in 'c1'
base = None; returning default value
... 1
c2.b = ...
'b' attribute not present in 'c2'
getting 'b' from base (c1)
... 55
c2.c = ...
... 99