如何在 Python 中访问超类的类属性? [英] How to access a superclass's class attributes in Python?
问题描述
看看下面的代码:
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
字典.
I have a hierarchy of classes each with its own dictionary containing some default values. If an instance of a class doesn't have a particular attribute, a default value for it should be returned instead. If no default value for the attribute is contained in the current class's defaults
dictionary, the superclass's defaults
dictionary should be searched.
我正在尝试使用递归类方法 get_default
来实现这一点.不幸的是,程序陷入了无限递归.我对 super()
的理解显然缺乏.通过访问 __mro__
,我可以让它正常工作,但我不确定这是一个合适的解决方案.
I'm trying to implement this using the recursive class method get_default
. The program gets stuck in an infinite recursion, unfortunately. My understanding of super()
is obviously lacking. By accessing __mro__
, I can get it to work properly though, but I'm not sure this is a proper solution.
我感觉答案就在这篇文章中,但我还没有找到它.也许我需要求助于使用元类?
I have the feeling the answer is somewhere in this article, but I haven't been able to find it yet. Perhaps I need to resort to using a metaclass?
在我的应用程序中,__getattr__
首先检查 self.base
.如果不是None
,则需要从那里获取该属性.只有在其他情况下,才必须返回默认值.我可能可以覆盖 __getattribute__
.那会是更好的解决方案吗?
edit: In my application, __getattr__
first checks self.base
. If it is not None
, the attribute needs to be fetched from there. Only in the other case, a default value must be returned. I could probably override __getattribute__
. Would that be the better solution?
编辑 2: 下面是我正在寻找的功能的扩展示例.它目前是使用 __mro__
实现的(unutbu 的早期建议,而不是我原来的递归方法).除非有人可以提出更优雅的解决方案,否则我很高兴使用此实现.我希望这能解决问题.
edit 2: Below is an extended example of the functionality that I'm looking for. It is currently implemented using __mro__
(unutbu's earlier suggestion, as opposed to my original recursive method). Unless someone can suggest a more elegant solution, I'm happy using this implementation. I hope this clears things up.
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
推荐答案
问题的第二次编辑中提出的解决方案仍然是唯一提供我的应用程序所需的一切的解决方案.虽然 unutbu 的代码可能更容易理解,但 __mro__
解决方案为 IMO 提供了一些优势(见评论).
The solution proposed in the second edit of the question is still the only one that provides everything my application requires. While unutbu's code might be simpler to understand, the __mro__
solution provides some advantages IMO (see comments).
这篇关于如何在 Python 中访问超类的类属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!