【问题标题】:Inherit multiple methods with same name from multiple classes从多个类继承多个同名方法
【发布时间】:2021-12-19 18:23:54
【问题描述】:

我有两个共享方法名称的父类。我想对它们进行子类化,并以不同的名称将它们的方法重新分配给子类。这很复杂,因为这些方法也使用具有共享名称的其他方法。人为但最小的例子:

class Foo1():
    def __init__(self):
        super().__init__()

    def print(self):
        print(self.get())

    def get(self):
        return 1


class Foo2():
    def __init__(self):
        super().__init__()

    def print(self):
        print(self.get())

    def get(self):
        return 2


class Foo(Foo1, Foo2):
    def __init__(self):
        super().__init__()

        self.print1 = super().print
        self.print2 = super(Foo1, self).print


foo = Foo()
foo.print1()
>>> 1
foo.print2()
>>> 1

在上面的例子中,foo.print1() 打印出 1,但是 foo.print2() 打印出 1 而不是 2。我想构造 Foo 使其调用 Foo2 的 print 和 get 方法,从而打印出 2。

我理解这是因为名称“self”实际上指向 Foo(),因此方法“print”和“get”指向 Foo1 的方法,因为 Foo1 在 MRO 中是第一个。

对于我的用例来说,Foo() 有“print”和“get”方法甚至没有意义,只有“print1”和“print2”。这让我怀疑我做错了。有没有更好的方法来构造一个从 Foo1 和 Foo2 正确继承这些方法的子类?

【问题讨论】:

  • 你想要组合,而不是继承。
  • 听起来你根本不想继承
  • @juanpa.arrivillaga 这就是我寻求指导的原因。我从未说过我“想要”继承。

标签: python multiple-inheritance method-resolution-order


【解决方案1】:

让您的类包装 Foo1Foo2 实例,而不是使用多重继承。

class Foo:
    def __init__(self):
        foo1 = Foo1()
        foo2 = Foo2()

        self.print1 = foo1.print
        self.print2 = foo2.print

        self.get1 = foo1.get
        self.get2 = foo2.get

【讨论】:

  • 这是否会像您在最初的评论中提到的那样考虑构图?我以前没听说过,但它看起来很简单。
  • 我不会制作print1 等人。实例属性。只需定义def print1(self): self.foo1.print()等即可
  • @chepner 这将涉及制作 foo1 和 foo2 实例属性,对吗?这样做有什么好处?
  • @Nevermore 您可能从未听说过这个术语,但您几乎可以肯定每次创建类时都会使用它
  • @Samwise 我实现了你的方式,但没有 self.get1 和 self.get2 方法,因为它们不需要为我的用例公开。谢谢!
【解决方案2】:

一种选择是使用组合,您的新类实例只是原始类的两个实例的包装器。您的方法将委托给适当实例的方法。

class Foo:
    def __init__(self):
        self.foo1 = Foo1()
        self.foo2 = Foo2()

    def print1(self):
        return self.foo1.print()

    def print2(self):
        return self.foo2.print()

    # etc

您还可以在类级别而不是实例级别执行组合。这仅在Foo1Foo2 方法的函数签名与Foo 方法的所需签名兼容时才有效。

class Foo:
    print1 = Foo1.print
    print2 = Foo2.print
    get1 = Foo1.get
    get2 = Foo2.get

在任何一种情况下,您都必须定义 Foo.__init__ 以接受 Foo1.__init__Foo2.__init__ 的任何必要参数,并确保将它们传递给正确的参数。

【讨论】:

  • 这行不通,因为 get1 和 get2 永远不会被任何东西调用。
  • 它们只是类属性,一旦您执行Foo().get1() 之类的操作就会访问它们;函数最初定义的在哪里并不重要。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-20
  • 1970-01-01
  • 2011-10-09
  • 2011-02-19
  • 1970-01-01
  • 2013-05-19
  • 1970-01-01
相关资源
最近更新 更多