Python - 子类从另一个子类调用一个函数

问题描述 投票:2回答:1

我有一个相当大的班级,我想把它分成几个小的班级,每个班级处理整体的一个部分。所以每个子类只负责整体的一个方面。

Example "Design" before and after

这些子类中的每个类仍然需要相互通信,例如Data Access创建了一个字典,Plotting Controller需要访问这个字典。然后Plotting Controller需要更新Main GUI Controller上的东西。但是这些子类还有各种更多的相互通信功能。

我如何实现这个功能?

我读过 元类, 合作性多继承合作式多重继承的奇迹但我不知道该怎么做。

我最接近的是下面的代码。

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

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

As shown here

Cannot find declaration

有什么好的方法可以实现这一点吗?或者说这其实是个坏主意?

编辑:Python 3.7,如果这有什么不同的话。

python multiple-inheritance metaclass
1个回答
1
投票

继承

当打破这样的类层次结构时,各个 "局部 "类,我们称之为 "mixins",将只 "看到 "直接在它们身上声明的内容,以及在它们的基类上声明的内容。在你的例子中,当编写类A时,它不知道任何关于类B的信息--作为作者,你可以知道来自类B的方法会存在,因为来自类A的方法只会被继承了这两个类的类C调用。

你的编程工具,包括IDE,都无法知道这些。(这一点你应该比你的编程辅助工具更清楚,是个旁门左道)。如果运行的话,是可以的,但这是一个糟糕的设计。

如果所有的方法都要直接出现在你的最终类的一个实例上,那么所有的方法都要 "出现 "在一个超级类中,供他们所有人使用--你甚至可以在不同的文件中写独立的子类,然后再写一个子类,继承所有的方法。

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 "是个小糖,它们会起作用,但这个设计没有这些也会起作用--我想它们的存在可以帮助看你代码的人弄清楚发生了什么,如果你错误地创建了一个不完整的基类的实例,就会在运行时出现错误)

复合材料

这样做是可行的,但如果你的方法实际上是针对不同的域,而不是多重继承,你应该尝试使用 "综合设计模式".

如果不自然产生,就不需要多重继承。

在这种情况下,你将驱动不同域的类的对象实例化在 __init__ 的实例,并将自己的实例传递给这些子类,子类将保留对它的引用(例如在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()
        ...


这个例子使用了基本的语言特性,但是如果你决定在一个复杂的应用程序中使用它,你可以将它复杂化--有接口模式,可以允许你在不同的领域,在专门的子类中交换使用的类,等等。但通常上面的模式是你需要的。

© www.soinside.com 2019 - 2024. All rights reserved.