Python - Child Class 调用另一个函数 Child Class

Python - Child Class to call a function from another Child Class

我有一个相当大的 class,我想分解成更小的 class,每个处理整体的一个部分。所以每个 child 只关注整体的一个方面。

这些 child class 中的每一个仍然需要相互通信。 例如,Data Access 创建了一个 Plotting Controller 需要访问的字典。 然后绘图控制器需要更新主 GUI 控制器上的内容。但是这些 children 还有更多 inter-communication 的功能。

我该如何实现?

我读过 Metaclasses, Cooperative Multiple Inheritence and Wonders of Cooperative Multiple Inheritence,但我不知道该怎么做。

我最接近的是以下代码:

class A:
    def __init__(self):
        self.myself = 'ClassA'

    def method_ONE_from_class_A(self, caller):
        print(f"I am method ONE from {self.myself} called by {caller}")
        self.method_ONE_from_class_B(self.myself)

    def method_TWO_from_class_A(self, caller):
        print(f"I am method TWO from {self.myself} called by {caller}")
        self.method_TWO_from_class_B(self.myself)


class B:
    def __init__(self):
        self.me = 'ClassB'

    def method_ONE_from_class_B(self, caller):
        print(f"I am method ONE from {self.me} called by {caller}")
        self.method_TWO_from_class_A(self.me)

    def method_TWO_from_class_B(self, caller):
        print(f"I am method TWO from {self.me} called by {caller}")


class C(A, B):

    def __init__(self):
        A.__init__(self)
        B.__init__(self)

    def children_start_talking(self):
        self.method_ONE_from_class_A('Big Poppa')


poppa = C()
poppa.children_start_talking()

正确的结果是:

I am method ONE from ClassA called by Big Poppa
I am method ONE from ClassB called by ClassA
I am method TWO from ClassA called by ClassB
I am method TWO from ClassB called by ClassA

但是...即使 Class B 和 Class A 正确调用了其他 children 的函数,他们实际上并没有找到他们的声明。当我输入代码时,我也 "see" 他们,这既令人沮丧又担心我可能做错了什么。

有什么好的方法可以实现吗?或者这实际上是个坏主意?

编辑:Python 3.7 如果有任何区别。

继承

当像这样打破class层次结构时,个体"partial" classes,我们调用"mixins",将"see"仅直接声明的在他们身上,在他们 base-classes 上。在您的示例中,当编写 class A 时,它对 class B 一无所知 - 作为作者,您可以知道来自 class B 的方法将会存在,因为来自 class A 只会从继承两者的 class C 调用。

您的编程工具,包括 IDE,无法知道这一点。 (你应该比你的编程助手更了解,这是一个旁路)。如果 运行,它会工作,但这是一个糟糕的设计。

如果所有方法都直接出现在最终 class 的单个实例上,所有方法都必须 "present" 在 super-class 中 - 你可以甚至在不同的文件中编写独立的子classes,然后一个单独的子class将继承所有的子class:

from abc import abstractmethod,  ABC

class Base(ABC):

    @abstractmethod
    def method_A_1(self):
        pass

    @abstractmethod
    def method_A_2(self):
        pass

    @abstractmethod
    def method_B_1(self):
        pass

class A(Base):
    def __init__(self, *args, **kwargs):
        # pop consumed named parameters from "kwargs"
        ...
        super().__init__(*args, **kwargs)
        # This call ensures all __init__ in bases are called
        # because Python linearize the base classes on multiple inheritance

    def method_A_1(self):
        ...

    def method_A_2(self):
        ...


class B(Base):
    def __init__(self, *args, **kwargs):
        # pop consumed named parameters from "kwargs"
        ...
        super().__init__(*args, **kwargs)
        # This call ensures all __init__ in bases are called
        # because Python linearize the base classes on multiple inheritance

    def method_B_1(self):
        ...

    ...


class C(A, B):
    pass

("ABC" 和 "abstractmethod" 有点甜 - 它们可以工作,但这个设计没有任何这些也可以工作 - 我认为它们的存在可以帮助任何正在查看你的代码的人理解弄清楚发生了什么,如果您每次错误地创建一个不完整基础 classes)

的实例,将会引发更早的 运行time 错误

复合

这行得通,但是如果您的方法实际上适用于截然不同的领域,那么 多重继承,你应该尝试使用 "composite design pattern".

如果不是自然产生的,则不需要多重继承。

在这种情况下,您在 shell class 的 __init__ 上实例化驱动不同域的 classes 中的 objects,并且将它自己的实例传递给那些 child,这将保留对它的引用(例如,在 self.parent 属性中)。很可能您的 IDE 仍然不知道您在说什么,但您的设计会更加明智。


class Parent:
    def __init__(self):
        self.a_domain = A(self)
        self.b_domain = B(self)

class A:
    def __init__(self, parent):
        self.parent = parent
        # no need to call any "super...init", this is called
        # as part of the initialization of the parent class

    def method_A_1(self):
        ...

    def method_A_2(self):
        ...


class B:
    def __init__(self, parent):
        self.parent = parent

    def method_B_1(self):
        # need result from 'A' domain:
        a_value = self.parent.a_domain.method_A_1()
        ...


这个例子使用了基本的语言特性,但是如果你决定 要在复杂的应用程序中使用它,您可以对其进行完善 - 有 接口模式,可以让你交换使用的 classes 对于不同的领域,在专门的子 classes 中,等等。但通常 上面的模式就是你需要的。