【问题标题】:In python, how to have two classes share implementation of a method that calls another method with specific implementations for each class在python中,如何让两个类共享一个方法的实现,该方法调用另一个方法,每个类都有特定的实现
【发布时间】:2020-09-25 15:37:45
【问题描述】:

假设我有一个父类Parent,其子类中实现了抽象方法load。现在,我有两个子类childAchildB,都继承自Parentload 的实现与childAchildB 相同。但是load 的这个实现调用了另一个方法get_paths,它特定于childAchildB。父母是这样的:

from abc import ABC, abstractmethod
class Parent(ABC):
    def __init__(self, *params):
        # set up the params

    @abstractmethod
    def load(self, *params):
        # loads files, according to each children

    def process(self, *params):
        # process the loaded files

然后是孩子们:

class childA(Parent):
    def __init__(self, *paramsP, *paramsA):
        super().__init__(*paramsP)
        # Set up the specific paramsA

    def get_paths(self, *params):
        # specific implementation to childA

    def load(self, *params):
        # Calls the self.get_paths method, identical to childB.load
class childB(Parent):
    def __init__(self, *paramsP, *paramsB):
        super().__init__(*paramsP)
        # Set up the specific paramsB

    def get_paths(self, *params):
        # specific implementation to childB

    def load(self, *params):
        # Calls the self.get_paths method, identical to childA.load

如何在childAchildB 中重用来自load 的代码,但get_paths 的实现是否特定于每个类?我尝试了两种方法:

(1) 让childB 改为从childA 继承,并覆盖get_paths 的实现。在这种方法中,我有:

class childB(childA):
    def __init__(self, *paramsP, *paramsB):
        super().__init__(*paramsP)
        # Set up the specific paramsB

    def get_paths(self, *params):
        # specific implementation to childB

我称之为:

b = childB(...)
b.load(...)

However, when I call `childB.load`, the `get_paths` called inside of it is `childA.get_paths`. I noticed that because I was getting an error when running `b.load`, so tried putting a break point with `ipdb` inside of `childB.get_paths`, but execution did not stop. But when I put the breaking point inside of `childA.get_paths`, it did break.

(2) Implement another class, `AB`, with the following definition:

```python
class AB(Parent):
    def __init__(self, *paramsP):
        super().__init__(*paramsP)

    @abstract method
    def get_paths(self, *params):
        # To be implemented in childA and childB

    def load(self, *params):
        # Implements the load from childA and childB

然后让childAchildB 都继承自AB,并实现它们特定的get_paths。但是,这也不起作用,因为我收到错误:TypeError: Can't instantiate abstract class ChildB with abstract methods _AB__get_paths

重要的是要添加我无法在Parent 中实现load,因为还有其他类(childCchildD、...)具有独特的load 实现。 .我只想在childAchildB 之间重用这段代码

那么,解决这个问题的正确方法是什么?

【问题讨论】:

  • 如果load() 在两个孩子中是相同的,为什么不把它放在父类上呢?我认为这应该是class childB(Parent) 而不是def childB(Parent)
  • 还有其他类继承自Parent,它们有不同的加载实现。是的,您对 defclass 的看法是正确的(:
  • "让 childB 继承自 childA,并覆盖 get_paths 的实现。但是,当我调用 childB.load 时,它内部调用的 get_paths 是 childA.get_paths" 嗯,它不应该是.你能展示你的实现以及你是如何使用它的吗?
  • 用这个描述更新了问题
  • 所以,我才找到原因。我错过了get_paths 是用__ 定义的事实,因此名称修改导致了各种问题。我将_ 替换为`__',它工作得很好。

标签: python python-3.x class inheritance


【解决方案1】:

除非您希望Parent 被抽象.load 继承,否则只需将实现放入Parent

如果.load 仅对这两个孩子通用——您可以从Parent 继承第三个孩子,如LoadMixin,并同时继承Parent 和mixin


一种方法是:

class LoadableChild(Parent):
    def load(self, *params): ...

class childA(LoadableChild):
    def get_paths(self, *params): ...

class childB(LoadableChild):
    def get_paths(self, *params): ...

另一个是:

class LoadBase:
    def load(self, *params): ...

class childA(LoadBase, Parent):
    def get_paths(self, *params): ...

class childB(LoadBase, Parent):
    def get_paths(self, *params): ...

注意后面方法的继承顺序,如果你继承父类作为第一个超类,没有简单的方法:

  • 如果你的 mixin 继承了 Parent - 没有明确的 MRO
  • 如果 mixin 继承 object - 抽象 .load 上存在实例化错误。

我会说这是偏好问题,对我个人而言,第一种方法更干净

【讨论】:

  • 我确实尝试了第一种方法,但是因为load 使用get_paths,我需要将其定义为LoadableChildParent 中的抽象方法,它是(2)我的问题中的例子。我这样做了,但是当我打电话给childB.load 时,我收到错误TypeError: Can't instantiate abstract class ChildB with abstract methods _LoadableChild__get_paths
  • 没有理由将load 定义为抽象方法,因为它调用了您希望子类覆盖的函数。
  • 是的,我添加为摘要是因为 linter 在抱怨(:。但你是对的。
猜你喜欢
  • 1970-01-01
  • 2019-10-27
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-01
  • 2021-10-13
相关资源
最近更新 更多