【问题标题】:Is it a good practice to put common methods to an abstract class in Python?将常用方法放在 Python 中的抽象类中是一种好习惯吗?
【发布时间】:2018-11-08 17:56:13
【问题描述】:

我正在使用abc 模块来定义子类必须支持的接口。所有子类中还存在一些通用方法。可以将它们放在抽象类中还是应该只包含抽象方法(即用@abc.abstractmethod装饰)?

【问题讨论】:

  • 通常接口和抽象类的区别在于接口没有字段,也没有实现任何方法。这两个概念都是有用的,具体取决于上下文。但是在 Python 中并没有明显的区别。但是在抽象类中实现方法并没有错。
  • 这样做有什么好处而不是使用raise NotImplementedError
  • @RockyLi 是的,继承自抽象类的类必须实现其所有抽象方法。
  • 绕过这个要求是微不足道的(abc 是一个库,而不是一个语言特性),但它仍然可以作为很好的文档和防止简单地忘记实现抽象方法的第一道防线。
  • 另外,将所有子类都应该可以访问的通用方法放在基类中是标准的OO实践,与基类是否抽象无关

标签: python inheritance abstract-class


【解决方案1】:

TL; DR; 是的,抽象类可以有非抽象方法。

通常我们所说的抽象类只是一个无法实例化的类。

另一方面,我们所说的接口是一个只有方法声明但没有实现的类。特别是它是一个抽象类,因为它没有构造函数。

当然,在 Python 中没有真正的接口:每个方法都必须有一个主体。但是我们可以通过raise NotImplementedError() 模拟一些接口。

无论如何,接口都是抽象类的子集。这显然表明存在不是接口的抽象类。这正是您所描述的情况。是的,抽象类可能包含已实现的非抽象方法。这不是一个坏习惯。这在给定方法不依赖于具体实现时特别有用。


例如考虑一个通用解析器的接口(我在考虑json.loadjson.loads):

class ILoader(ABC):
    @abstractmethod
    def load(self, stream):
        raise NotImplementedError()

loads 方法提供一个接受字符串而不是默认实现的流是完全可以的:

class AbstractLoader(ABC):
    @abstractmethod
    def load(self, stream):
        raise NotImplementedError()

    def loads(self, text):
        stream = io.StringIO(text)
        return self.load(stream)

虽然我会使用Abstract 前缀而不是I。 ;)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-20
    • 2018-09-26
    • 1970-01-01
    • 2017-07-15
    • 1970-01-01
    • 2022-01-20
    • 2019-12-28
    • 2017-06-14
    相关资源
    最近更新 更多