获取 Python 中超级 class 的类型 3

Get the type of the super class in Python 3

我有一个基础 class,其中有两个 class 派生自它。我希望基础 classes 的方法根据参数是否与派生 class 具有相同类型或仅是基础 class 的实例但类型不同而表现不同.这是当前的实现:

class MyBase:
    def __init__(self, foo: int):
        self.foo = foo 

    def __eq__(self, other):
        return self.foo == other.foo 


class MyDerived_1(MyBase):
    def __init__(self, foo: int, bar: int):
        super().__init__(foo)
        self.bar = bar


class MyDerived_2(MyBase):
    def __init__(self, foo: int, bar: int):
        super().__init__(foo)
        self.bar = bar 

    def __eq__(self, other):
        if type(other) == type(self):
            return self.bar == other.bar 
        elif isinstance(other, MyBase):
            return super().__eq__(other)
        else:
            return False

在倒数第四行中,我必须明确引用 MyBase。也许这很好,但我的理解是 "super" 关键字的一个要点是它应该允许您更改基础 class 而不必在 class 中重写任何内容。所以我。这个解决方案的一个潜在问题是,如果 MyBase 被更改,那么 init 会很好,因为它调用 "super",但 eq 不会更新其行为。

所以我尝试将 "MyBase" 替换为 "type(super)" 或 "type(super())",但这些不引用超级 class,它们引用 class对象 "super".

请注意,此问题不同于:

Get parent class name? Get defining class of unbound method object in Python 3 等等

因为一旦对象被初始化,他们就会寻找父 classes。

我想我应该可以通过 运行 找到超级 class MRO。但这似乎是一个糟糕的解决方案,因为我不是在寻找整个继承树,我只是想知道超级 class.

的类型

有没有办法从 "super" 中提取该信息?

首先你要在遇到不支持的类型时从__eq__returnNotImplemented,这样Python也可以给第二个操作数有机会参加相等性测试。来自 Python datamodel documenation:

Numeric methods and rich comparison methods should return this value if they do not implement the operation for the operands provided. (The interpreter will then try the reflected operation, or some other fallback, depending on the operator.)

other 不是同一类型的实例时,您的代码实际上应该只委托给 super().__eq__(),这里不需要测试基类型;基础 class 应该已经负责测试正确的类型或协议。

接下来,您可以使用 Python 3 __class__ closure 访问定义方法的 class; Python 在嵌套在 class 定义中的函数定义中使用 super()__class__ 时添加此闭包:

class MyBase:
    # ...

    def __eq__(self, other):
        if not isinstance(other, __class__):
            # we can't handle the other type, inform Python
            return NotImplemented
        return self.foo == other.foo 

class MyDerived_2(MyBase):
    # ...

    def __eq__(self, other):
        if isinstance(other, __class__):
            # if other is an instance of MyDerived_2, only test for 'bar'
            return self.bar == other.bar 
        # otherwise fall back to the base behaviour
        return super().__eq__(other)

请注意,我使用了 isinstance() 而不是 type() 测试,您需要 subclasses of MyDerived_2继承这种行为。

除了测试特定的 class 层次结构,您还可以依赖 duck-typing;如果另一个对象具有正确的属性名称,则假设它可以用于比较:

class MyBase:
    # ...

    def __eq__(self, other):
        try:
            self.foo == other.foo
        except AttributeError:
            # we can't handle the other type, inform Python
            return NotImplemented

class MyDerived_2(MyBase):
    # ...

    def __eq__(self, other):
        try:
            self.bar == other.bar
        except AttributeError:
            # otherwise fall back to the base behaviour
            return super().__eq__(other)

我认为您可能需要使用 inspect 模块及其 getclasstree() 功能:https://docs.python.org/3/library/inspect.html#inspect.getclasstree

class MyDerived_2(MyBase):

    def mytree(self):
        print(inspect.getclasstree([self.__class__]))


c = MyDerived_2(1, 2)
c.mytree()

这输出:

[(<class '__main__.MyBase'>, (<class 'object'>,)), [(<class '__main__.MyDerived_2'>, (<class '__main__.MyBase'>,))]]