如何在 Python 中访问超类的类属性? [英] How to access a superclass's class attributes in Python?

查看:35
本文介绍了如何在 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆