使用 __getattr__ 方法作为组合模式是良好的 Python 实践吗?

cle*_*ros 5 python object-composition

首先 - 如果这是重复的,请接受我的道歉 - 我有一种感觉,我以前见过某种类似的讨论,但我真的找不到它。

我的问题是关于 Python 中的对象组合,它应该看起来像是从复合类的每个次要类中继承的。用例是多个对象实例共享属性及其值的公共核心(而不仅仅是公共结构,这将是经典的继承情况)。

我可以使用一个简单的属性来做到这一点,即只需让每个类都有一个名为“shared_attributes”的属性,该属性本身就是一个存储所有值的类:

class CoreClass(object):
    def __init__(self):
        self.attr = 'asdf'


class CompClass1(object):
    def __init__(self, core):
        self.core_attr = core


class CompClass2(object):
    def __init__(self, core):
        self.core_attr = core
Run Code Online (Sandbox Code Playgroud)

但这要求我通过属性访问每个共享属性class.core_attr,这是我不想要的(出于多种原因,其中之一是这需要对大段代码进行大量重写)。

因此,我想使用依赖于 Python 内置__getattr__对象方法的复合模式,如下所示:

class TestClass1(object):
    def __init__(self):
        self.attr1 = 1

    def func_a(self):
        return 'a'


class CompClassBase(object):
    def __init__(self, test_class):
        self.comp_obj = test_class

    def __getattr__(self, item):
        return getattr(self.comp_obj, item)


class CompClass1(CompClassBase):
    def __init__(self, test_class):
        CompClassBase.__init__(self, test_class)
        self.attr2 = 13

    def func_b(self):
        return '1b'


class CompClass2(CompClassBase):
    def __init__(self, test_class):
        CompClassBase.__init__(self, test_class)
        self.attr2 = 23

    def func_b(self):
        return '2b'


if __name__ == '__main__':
    tc = TestClass1()
    cc1 = CompClass1(test_class=tc)
    cc2 = CompClass2(test_class=tc)
    print cc1.attr1
    print cc1.attr2
    print cc1.func_a()
    print cc1.func_b()
    print cc2.attr1
    print cc2.attr2
    print cc2.func_a()
    print cc2.func_b()
Run Code Online (Sandbox Code Playgroud)

它应该打印以下内容:

1
13
a
1b
1
23
a
2b
Run Code Online (Sandbox Code Playgroud)

这种模式完全符合我的需求,但它有一些东西想让我确定它......

编辑:(回应一些评论)此模式必须共享共享类中的所有属性(给定前面的对象):

cc1.attr1 = 'this is a test'
cc2.attr1  # must now be 'this is a test' as well!
Run Code Online (Sandbox Code Playgroud)

第二次编辑:我已经使用这种模式几个星期了,而且效果很好。但是,我仍然希望进行一些讨论,因为我想从现在开始将这种模式包含在我的标准工具包中:-)

所以现在我问你的问题很简单:这是一个好的做法吗?这种特定的 Python 模式有什么缺点吗?我应该注意这里的一些危险吗?