【问题标题】:Python - Calling __init__ for multiple parent classesPython - 为多个父类调用 __init__
【发布时间】:2016-09-09 15:31:35
【问题描述】:

编辑:我正在使用 Python 3

我有一个类X 扩展了YZ

class X(Y, Z):
    def __init__(self):
    # Call Y's __init__
    # Call Z's __init
    pass

我需要在X 上的__init__ 上同时拨打YZ 上的__init__。最好的方法是什么?

【问题讨论】:

  • 这是 Python 2 还是 3?
  • 我在 Python 3 上。
  • 这是另一个原因,为什么多重继承 - 不好,那么在这种不好的做法中如何询问最佳做法?
  • 好的,我删除了关于最佳实践的部分。现在你有什么建议?

标签: python-3.x


【解决方案1】:

这完全取决于YZ 是否被设计 用于与多重继承协同工作。如果是,那么您应该可以使用super

class X(Y, Z):
    def __init__(self):
        super().__init__()

当我说YZ 需要设计为与多重继承协同工作时,我的意思是它们还必须在__init__ 方法中调用super:

class Y:
    def __init__(self):
        print('Y.__init__')
        super().__init__()

class Z:
    def __init__(self):
        print('Z.__init__')
        super().__init__()

他们还应该有一些策略来处理不同的参数,因为(尤其是构造函数)一个类的不同之处在于它们接受的关键字参数。在这一点上,值得阅读Super considered super!Super considered harmful来了解一些关于super的常见习语和陷阱。

如果您不知道 YZ 是否设计用于协作多重继承,那么最安全的方法是假设它们不是。


如果这些类不是设计用于协作多重继承,那么您需要开始轻而易举地开始(您处于危险水域)。您可以分别致电每个__init__

class X(Y, Z):
    def __init__(self):
        Y.__init__(self)
        Z.__init__(self)

但真的最好不要使用多重继承,而是选择不同的范例(例如组合)。

【讨论】:

  • 在我的情况下,父母是 - threading.Threadlogging.Handler - 我如何检查他们是否设计为在多重继承中协同工作?
  • 据我所知,threading.Thread 没有。
  • @masnun 您需要问自己的问题是:为什么要从他们两个继承?您正在混合不相关的概念。使用一个将它们都作为字段(或其他一些干净的模式)的类会更干净。
  • @mgilson 我猜Handler 也不使用super。我可以看到它在自己的__init__ 中调用Filterer.__init__(self)。谢谢你的解释。
  • 假设 Y 也有一个基类 (Q) 并且 Y 调用 super().__init__() 以确保它(隐式)调用 Q.__init__()。根据方法解析顺序,Ysuper().__init__() 可能实际上调用Z.__init__ 而不是Q.__init__。如果Z.__init__ 也是supers,那么您将调用Z.__init__ 两次(一次在这里,一次明确地稍后)。如果Z.__init__ 没有super,那么您可能会完全跳过Q.__init__
【解决方案2】:

一般没有其他方法,只能直接调用Y.__init__(self)Z.__init__(self)。这是确保两个构造函数至少调用一次的唯一方法。

但是在一些奇怪的(或正常的,取决于你如何看待它)的情况下,这可能会导致多次调用基本构造函数的非常不直观的结果:

class Y:
    def __init__(self):
        print('Y')
        super().__init__()

class Z:
    def __init__(self):
        print('Z')
        super().__init__()

class X(Y, Z):
    def __init__(self):
        print('X')
        Y.__init__(self)
        Z.__init__(self)

X()

结果

X
Y
Z
Z

因此,在这种情况下,X 中的super().__init__()(而不是两个.__init__() 调用)看起来很自然并且可以正常工作。但是,如果 YZ 也不调用 super().__init__(),它将失败。在这种情况下,您只会调用其中一个构造函数。

所以一般来说,如果不知道基类的实现,就无法正确解决您的问题。

YARtAMI = 避免多重继承的另一个原因

【讨论】:

  • 感谢您的详细解释。在我的例子中,没有一个父类有任何共同的祖先。
  • @masnun 他们不必有。我已经更新了答案。
  • 有什么解释可以理解为什么Y中的第一个调用super().__init__()会触发Z.__init__()???我理解 Y 和 Z 继承自 object,所以我不明白为什么第一个“Z”会打印在屏幕上
猜你喜欢
  • 2010-11-26
  • 1970-01-01
  • 2013-06-20
  • 1970-01-01
  • 1970-01-01
  • 2021-10-19
  • 2011-12-22
  • 2021-10-21
相关资源
最近更新 更多