关于继承:获取python 3中超级super类的类型

Get the type of the super class in Python 3

我有一个基类,有两个派生自它的类。我希望基类的方法的行为有所不同,这取决于参数是否与派生类属于同一类型,或者仅是基类的实例,但类型不同。这是当前的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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"关键字的一个主要点是它应该允许您更改基类,而不必在类中重新编写任何内容。因此,也就是说,这个解决方案的一个潜在问题是,如果mybase被更改,那么init会很好,因为它称为"super",但是eq不会更新它的行为。

所以我试图用"type(super)"或"type(super())"替换"mybase",但这些并不引用超级类,而是引用对象"super"的类。

请注意,此问题不同于:

获取父类名称?获取python 3中未绑定方法对象的定义类等。

因为一旦对象被初始化,它们就在寻找父类。

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

有没有办法从"超级"中提取信息?


首先,当遇到不支持的类型时,希望从__eq__返回NotImplemented,这样python也可以给第二个操作数一个参与相等测试的机会。从python数据模型文档:

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__(),这里不需要测试基类型;基类应该已经负责测试正确的类型或协议。

接下来,可以使用python 3 __class__闭包访问在其上定义方法的类;每当在嵌套在类定义内的函数定义中使用super()__class__时,python都会添加此闭包:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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()测试,您希望MyDerived_2的子类继承这种行为。

除了测试特定的类层次结构之外,您还可以依赖duck类型;如果另一个对象具有正确的属性名,那么假设它可以用于比较:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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.getclassstree

1
2
3
4
5
6
7
8
class MyDerived_2(MyBase):

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


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

此输出:

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