【问题标题】:How can I create an abstract class that inherits from an abstract class in Python?如何创建一个继承自 Python 中的抽象类的抽象类?
【发布时间】:2019-12-05 01:01:40
【问题描述】:

我想定义一个继承自另一个抽象类的抽象类。

class DataBuffer(ABC):
    def __init__(self):
        self.buffered_data = {}

class IMUDataBuffer(ABC, DataBuffer):
    def __init__(self):
        super(IMUDataBuffer, self).__init__()

    def update(self, message):
        timestamp = message['ts']
        x_val, y_val, z_val = message[self.message_key]
        self.buffered_data[timestamp] = (x_val, y_val, z_val)

class GyroscopeDataBuffer(IMUDataBuffer):
    def __init__(self):
        super(GyroscopeDataBuffer, self).__init__()
        self.message_key = 'gy'

class AccelerometerDataBuffer(IMUDataBuffer):
    def __init__(self, message):
        super(AccelerometerDataBuffer, self).__init__()
        self.message_key = 'ac'

在这个例子中,IMUDataBuffer 应该从 DataBuffer 继承方法,但它本身永远不会被实例化,因此应该是一个抽象类。

这是我使用上述代码收到的错误:

TypeError: Cannot create a consistent method resolution order (MRO) for bases ABC, DataBuffer

作为一种廉价的解决方法,我可以在 IMUDatabuffer 中定义一个 message_key,但这对我来说感觉很草率,因为实际上 IMUDataBuffer 不应该有 message_key 属性。

class IMUDataBuffer(DataBuffer):
    def __init__(self):
        super(IMUDataBuffer, self).__init__()
        self.message_key = None

这里处理继承的正确方法是什么?

【问题讨论】:

    标签: python abstract-class multiple-inheritance


    【解决方案1】:

    我建议删除 IMUDataBuffer 父列表中的 ABC,因为 DataBuffer 已经有 ABC 作为父列表。

    ABC -> DataBuffer -> IMUDataBuffer -> Gyroscope
                                       -> Accelerometer
    

    代码如下所示:

    class ABC:
        pass
    
    class DataBuffer(ABC):  # <-- brings already all stuff from ABC
        def __init__(self):
            self.buffered_data = {}
    
    class IMUDataBuffer(DataBuffer):  # <-- ABC removed here
        def __init__(self):
            super(IMUDataBuffer, self).__init__()
    
        [...]
    

    然后错误消失。

    【讨论】:

    • 谢谢!这似乎可行,但我从 pycharm 获得了 message_key 变量的“未解析的属性引用”。有没有可能这门课还没有真正被认可为 ABC?
    • 您可以从 Python 中的多个类继承。但在这种情况下,没有必要。
    • @KevinKing ABC 的类定义是什么? IMUDataBuffer中不存在self.message_key是对的,Pycharm完全正确。
    • ABC 是默认 abc 库中的 AbstractBaseClass。 from abc import ABC
    • ABC 在我看来就像 foo, bar, 123... 我会看看文档。谢谢,@KevinKing!
    【解决方案2】:

    这里是修复 -

    from abc import *
    
    class DataBuffer(ABC):
        def __init__(self):
            self.buffered_data = {}
    
    class IMUDataBuffer(DataBuffer, ABC):
        def __init__(self):
            super(IMUDataBuffer, self).__init__()
    
        def update(self, message):
            timestamp = message['ts']
            x_val, y_val, z_val = message[self.message_key]
            self.buffered_data[timestamp] = (x_val, y_val, z_val)
    

    另请参阅此处以获取详细说明- Why is this an ambiguous MRO?

    【讨论】:

    • 这看起来很接近,但是当我尝试实例化 GyroscopeDataBuffer 类时,我得到一个TypeError: __new__() missing 3 required positional arguments: 'name', 'bases', and 'namespace'
    • 我已经更新了代码。我使用的是 python 2.7。针对 python 3 更正了它。查看您的代码在这里工作 - repl.it/repls/DetailedAngryInstitution
    【解决方案3】:

    在 Python 中,简单地从 ABC 继承并不会阻止实例化。这工作正常:

    from abc import ABC
    
    class Foo(ABC):
        pass
    
    foo = Foo()
    

    如果有未实现的abstractmethods,实例化只会引发错误。

    您的中间类不必继承自 ABC,只需继承自 DataBuffer。只要有未实现的abstractmethods 实例化就会失败。

    from abc import ABC, abstractmethod
    
    class Foo(ABC):
        @abstractmethod
        def do_thing(self):
            pass
    
    class Bar(Foo):
        pass
    
    bar = Bar()  # Instantiation raises TypeError because Bar does not implement do_thing
    

    由于 Bar 继承自 Foo 是一个抽象类,所以 Bar 也是一个抽象类:

    >>> type(Foo)
    <class 'abc.ABCMeta'>
    >>> type(Bar)
    <class 'abc.ABCMeta'>
    

    与其他一些随机类比较:

    >>> class Baz:
    >>>    pass
    >>> type(Baz)
    <class 'type'>
    

    【讨论】:

      猜你喜欢
      • 2018-06-28
      • 1970-01-01
      • 2019-12-30
      • 1970-01-01
      • 2021-10-24
      • 1970-01-01
      • 1970-01-01
      • 2012-11-15
      • 1970-01-01
      相关资源
      最近更新 更多