获取Python 3中超类的类型

时间:2019-01-03 10:46:32

标签: python inheritance super superclass

我有一个基类,有两个从其派生的类。我希望基类的方法表现不同,这取决于参数是与派生类属于同一类型,还是仅是基类的实例但具有不同的类型。这是当前的实现:

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”的类。

请注意,此问题与以下内容不同:

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

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

我想我应该可以通过运行MRO来找到超类。但是,鉴于我不是要查找整个继承树,而是只想知道超类的类型,所以这似乎是一个糟糕的解决方案。

有没有办法将这些信息从“超级”中拉出来?

2 个答案:

答案 0 :(得分:1)

首先,当遇到不支持的类型时,您想从NotImplemented返回__eq__,以便Python也可以使第二个操作数有机会参与相等性测试。来自Python datamodel documenation

  

数值方法和丰富比较方法如果未实现所提供操作数的操作,则应返回此值。 (然后,取决于操作员,解释器将尝试执行反射操作或其他一些后备操作。)

super().__eq__()不是相同类型的实例时,您的代码实际上应该仅委托给other,在这里无需测试基本类型;基类应该已经在测试正确的类型或协议。

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

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子类继承此行为。

除了测试特定的类层次结构之外,您还可以依赖鸭子类型。如果另一个对象具有正确的属性名称,则只需假设它可以与以下对象进行比较即可:

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)

答案 1 :(得分:0)

我认为您可能需要使用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'>,))]]