Mat*_*att 36 python java abstract-class interface
我有许多类都共享相同的方法,只有不同的实现.在Java中,让每个类实现一个接口或扩展一个抽象类是有意义的.Python有没有类似的东西,或者我应该采取替代方法?
Kat*_*iel 61
Python中的接口背后有一个故事.多年来一直占据主导地位的原始态度是你不需要它们:Python在EAFP(更容易请求宽恕而非许可)原则上工作.也就是说,不是指定你接受一个,我不知道,ICloseable对象,你只close
需要在需要时尝试该对象,如果它引发异常,则会引发异常.
因此,在这种心态中,您只需单独编写类,并按照自己的意愿使用它们.如果其中一个不符合要求,您的程序将引发异常; 相反,如果您使用正确的方法编写另一个类,那么它将正常工作,而无需指定它实现您的特定接口.
这非常有效,但接口有明确的用例,特别是对于较大的软件项目.Python中的最终决定是提供abc
模块,它允许您编写抽象基类,即除非覆盖所有方法,否则无法实例化的类.您是否认为使用它们是值得的,这是您的决定.
该PEP引入基本知识讲解比我好很多:
在面向对象编程领域,与对象交互的使用模式可以分为两个基本类别,即"调用"和"检查".
调用意味着通过调用其方法与对象进行交互.通常这与多态性结合使用,因此调用给定方法可能会根据对象的类型运行不同的代码.
检查意味着外部代码(在对象的方法之外)检查该对象的类型或属性的能力,并根据该信息决定如何处理该对象.
两种使用模式都服务于相同的一般目的,即能够以统一的方式支持处理各种各样的和可能新颖的对象,但同时允许为每种不同类型的对象定制处理决策.
在经典的OOP理论中,调用是首选的使用模式,并且主动不鼓励检查,被认为是早期程序编程风格的遗留物.然而,在实践中,这种观点过于教条和缺乏灵活性,并且导致一种设计刚性,这与Python之类的语言的动态性质非常不一致.
特别是,通常需要以对象类的创建者未预料到的方式处理对象.构建满足该对象的每个可能用户需求的每个对象方法并不总是最佳解决方案.此外,有许多强大的调度原理与经典的OOP行为要求形成鲜明对比,行为被严格封装在一个对象中,例如规则或模式匹配驱动的逻辑.
另一方面,经典OOP理论家对检查的批评之一是缺乏形式主义和被检查的临时性质.在诸如Python之类的语言中,对象的几乎任何方面都可以被外部代码反射和直接访问,有许多不同的方法来测试对象是否符合特定协议.例如,如果询问'这个对象是一个可变序列容器吗?',可以查找'list'的基类,或者可以查找名为' getitem ' 的方法.但请注意,尽管这些测试看似显而易见,但它们都不正确,因为一个产生假阴性,另一个产生假阳性.
普遍认可的补救措施是使测试标准化,并将它们分组为正式的安排.通过将每个类与一组标准可测试属性相关联,可以通过继承机制或其他方式轻松完成.每个测试都带有一组promise:它包含对类的一般行为的承诺,以及对其他类方法可用的承诺.
该PEP提出了组织这些测试的特定策略,称为抽象基类(ABC).ABCs只是Python类,它们被添加到对象的继承树中,以向外部检查器发送该对象的某些特征.使用isinstance()进行测试,并且特定ABC的存在意味着测试已通过.
此外,ABCs定义了一组最小的方法,用于建立类型的特征行为.根据ABC类型区分对象的代码可以相信这些方法将始终存在.这些方法中的每一个都伴随着广义的抽象语义定义,该定义在ABC的文档中描述.这些标准语义定义未强制执行,但强烈建议使用.
与Python中的所有其他内容一样,这些承诺具有绅士协议的性质,在这种情况下意味着虽然语言确实执行了ABC中的一些承诺,但是由具体类的实施者来确保保留其余的.
也许你可以使用这样的东西。这将充当抽象类。因此每个子类都被迫实现 func1()
class Abstract:
def func1(self):
raise NotImplementedError("The method not implemented")
Run Code Online (Sandbox Code Playgroud)
我对 Python 不太熟悉,但我敢猜测它不熟悉。
Java 中存在接口的原因是它们指定了一个协定。java.util.List
例如,实现 的东西保证有一个add()
方法来符合接口上定义的一般行为。您可以在不知道其特定类的情况下插入 List 的任何(理智)实现,调用接口上定义的一系列方法并获得相同的一般行为。
此外,开发人员和编译器都可以知道这样的方法存在并且可以在所讨论的对象上调用,即使他们不知道它的确切类。这是一种多态形式,静态类型需要它来允许不同的实现类,但仍然知道它们都是合法的。
这在 Python 中没有任何意义,因为它不是静态类型的。你不需要声明一个对象的类,也不需要让编译器相信你正在调用它的方法肯定存在。鸭子类型世界中的“接口”就像调用方法并相信对象可以适当地处理该消息一样简单。
注意 - 欢迎来自知识渊博的 Pythonistas 的编辑。