【问题标题】:Python loop over non-inherited attributes in base classPython循环遍历基类中的非继承属性
【发布时间】:2019-02-01 14:43:08
【问题描述】:

我有一个包含数字属性的基类,这些属性在初始化时作为字典简单地传递给它,然后添加到实例的字典中:

class baseclass(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

    def calcValue(self):
        return sum(vars(self).values())

现在我有一个从这个类派生的类,它为类添加了额外的属性,例如;

class childclass(baseclass):
    def __init__(self, stringValue, **kwargs):
        super(childclass, self).__init__(kwargs)
        self.name = stringValue

现在我想在我的基类中有一个函数,它只遍历添加到类中的所有属性,而不是作为子属性添加的属性。例如,如果我像这样创建一个子类的实例:

instance = childclass("myname", a=1, b=2, c=3)

然后调用calcValue方法,应该返回1+2+3 = 6

instance.calcValue()

但是由于 vars(self) 将返回完整的字典,不包括 childclass 属性中的字符串,当然不能添加。有没有办法只访问属于各自派生类的实例的属性?

【问题讨论】:

  • 如果我遇到这样的问题,我会考虑设计是否正确。如果您想分离事物,请以一种或另一种方式明确分离。

标签: python python-3.x inheritance


【解决方案1】:

您将所有属性作为普通值存储在实例的__dict__ 上。这意味着如果没有任何进一步的提示,它们就无法区分。

Python 有一些机制可以以特殊方式处理属性。如果您在类本身中声明基类中的属性,并在 __init__ 方法中初始化它们的值,则可以内省基类的 __dict__(而不是实例的 __dict__),或同一类中的__annotations__ 属性。

就像在示例中一样,一件简单的事情是使用特殊属性来记录添加到基类上的属性,然后您可以将其作为属性名称来源进行查阅:

class baseclass(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)
        self._numeric_attrs = set(kwargs.keys())

    def calcValue(self):
        return sum(getattr(self, attr) for attr in self._numeric_attrs)

【讨论】:

    【解决方案2】:

    一种简单、安全且有效的方法——但会增加开销——将基类属性存储在一个不同的属性中,并使用__getattr__ 为它们提供服务:

    class BaseClass(object):
        def __init__(self, **kwargs):
            self._attribs = kwargs
    
        def __getattr__(self, name):
            try:
                return self._attribs[name]
            except KeyError:
                raise AttributeError("object {} has no attribute {}".format(type(self).__name__, name))
    
        def calcValue(self):
            return sum(self._attribs.values())
    

    我通常会尽量避免使用__getattr__,因为它会使代码更难检查和维护,但由于您的类已经没有明确的 API,因此在这里没有太大区别。

    【讨论】:

    • 这样做会阻止属性被更改,但要显式修改__attribs 字典。将这些属性保存在单独的数据结构中显然是一种解决方案,但必须小心。
    • @jsbueno 确实。
    猜你喜欢
    • 1970-01-01
    • 2023-01-11
    • 1970-01-01
    • 2012-07-05
    • 1970-01-01
    • 1970-01-01
    • 2015-08-09
    • 2014-05-16
    • 1970-01-01
    相关资源
    最近更新 更多