8

我将 mixin 理解为看起来像继承但更像是组合的东西。
(编辑:我倾向于giving additional functionality/attributes用 mixin 而不是giving another is-a relationship.)
在心理上,当我使用 mixin 时,我会说这样的话:我给你这个 mixin 你缺少了,而不是你实际上也是这个 mixin 类型。 (是一个)

我读了几次,你应该更喜欢组合而不是继承。

我们可以直接使用组合而不是 mixin,mixin 是干什么用的?

如果我不得不猜测,那是因为 my_instance.foo() 比 my_instance.another_instance.foo() 更容易?
(如果 mixin 有 foo(),则可以使用 my_instance.foo(),将 another_instance 合成为 my_instance 的属性时需要 my_instance.another_instance.foo())

还有其他原因吗?


编辑:

因此,即使我觉得它是 has-a,mixin 仍然是 is-a 关系。并在您使用 is-a 时获得的好处是,界面更简洁。这就是我如何解释德尔南的回答。

4

1 回答 1

10

(因为 mixin 没有给你 is-a 关系,它给了你 has-a)

错了,它确实给了你一个is-a关系。考虑class C(A, B)issubclass(C, A)是真的,也是issubclass(C, B)。如果 B 的方法没有在 MRO 中的某个地方被覆盖(这也可能发生在单继承中!),则调用C().method_of_B()调用 B 的方法,对于A. 属性访问C().attr_of_{a,b}为您提供了Aor Btoo 的属性(与方法相同的警告)。

我读了几次,你应该更喜欢组合而不是继承。

存在这个经验法则是因为许多人倾向于在不合适的地方使用继承,而不是因为在任何情况下继承都不是有用的工具。这也适用于 Python。常见(好的)原因包括:

  • is-a 关系是错误的,例如因为它违反了 Liskov 替换原则。这个原因不受 mixins 的影响,见上文。
  • 由于各种原因,组合更容易或更不容易出错。这个理由在 mixins 也是可能的情况下也是有效的,如果它被放大的话,因为它可能有点棘手(尽管并非不可能)来获得正确的 MRO 和super()调用顺序。

如果我不得不猜测,那是因为 my_instance.foo() 比 my_instance.another_instance.foo() 更容易?

这只是几个额外的字符。更重要的是,您必须为要重新导出的每个方法重新键入包装器方法(如果您通过组合模拟 is-a 关系,这将是所有方法)。

C从概念上讲,如果真的是-a,这项手动工作似乎毫无意义且容易出错A。Mixins/多重继承支持对象多于可以或应该由单个低音类表示的情况。例如,UTF-8 字符串可能既是 aByteBuffer又是 a UnicodeStream。一般来说,我们有这个接口(或者没有接口;在 Python 中这是隐式的),但是 mixins 也允许以可组合和方便的方式添加相关功能。

于 2013-07-13T14:07:09.030 回答