基于 David Beazley 的一些代码理解多重继承和超类

Understanding multiple inheritence and super based on some code from David Beazly

我看过 David Beazly 的 screencast,他在其中使用多个或更具体的菱形继承来实现类型检查。我认为他的方法看起来很酷,但它也让我感到困惑,我根本无法弄清楚它是如何工作的。这是我正在谈论的代码:

class Contract:
    @classmethod
    def check(cls, value):
        pass


class Integer(Contract):
    @classmethod
    def check(cls, value):
        assert isinstance(value, int), 'Expected int'
        super().check(value)


class Positive(Contract):
    @classmethod
    def check(cls, value):
        assert value > 0, 'Must be > 0'
        super().check(value)


class PositiveInteger(Positive, Integer):
    pass

它正在运行:

>>> PositiveInteger.check(-3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in check
AssertionError: Must be > 0
>>> PositiveInteger.check(4.88)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in check
  File "<stdin>", line 4, in check
AssertionError: Expected int

我的问题是:

  1. 为什么要定义一个基础 class 合同并进行方法检查才能使这项工作正常进行?

  2. 我对super的作用有了基本的了解。我知道它让我们避免显式调用基 class 并以某种方式处理多重继承。但是在这个例子中它到底做了什么?

让我们像调试器一样逐行检查它。

PositiveInteger.check(x)

# Method resolution order:
# PositiveInteger, Positive, Integer, Contract (from Positive), Contract (from Integer)

# Look through MRO for .check() method. Found in Positive.

assert x > 0
super().check(value)

# super() checks for next .check() method in MRO. Found in Integer

assert isinstance(x, int)
super().check(value)

# super() checks for next .check() method in MRO. Found in Contract

pass

要轻松找到方法解析顺序,请使用 inspect.getmro()

如果在 Positive 之后显式使用基数 class,则基数 class 是 Contract,因此永远不会调用 Integer

你需要在Contract中定义.check()作为你调用最后一个super()的时候,如果Contract没有.check()方法,它会引发 AttributeError,因为 super() 无法找到它。