不应实例化的类

时间:2017-03-16 14:53:12

标签: python python-3.x class inheritance

我想创建一个类层次结构,其中我有一个类Block,可以自己实例化。然后我有一个继承自List的类Block并包含所有列表共有的方法,最后我有从{{1}继承的类OrderedListLableledList等}。我希望人们能够实例化List等,但不能OrderedList

换句话说,您可以实例化普通List,并且可以实例化继承自Block的{​​{1}}的{​​{1}},但您无法实例化OrderedList

Google的所有尝试都会导致抽象基类,但没有提供符合这种情况的例子,我在推断时遇到了麻烦。

4 个答案:

答案 0 :(得分:2)

以下与口译员的对话应该说明这是如何实现的。从Block继承抽象基类后,您只需要将List上的初始化程序标记为abstractmethod。这将阻止类的实例化,而不会导致子类出现问题。

>>> import abc
>>> class Block(abc.ABC):
    def __init__(self, data):
        self.data = data


>>> class List(Block):
    @abc.abstractmethod
    def __init__(self, data, extra):
        super().__init__(data)
        self.extra = extra


>>> class OrderedList(List):
    def __init__(self, data, extra, final):
        super().__init__(data, extra)
        self.final = final


>>> instance = Block(None)
>>> instance = List(None, None)
Traceback (most recent call last):
  File "<pyshell#42>", line 1, in <module>
    instance = List(None, None)
TypeError: Can't instantiate abstract class List with abstract methods __init__
>>> instance = OrderedList(None, None, None)
>>> 

答案 1 :(得分:1)

继承ABC模块中的abc并创建在基类中实现的方法(继承自List@abstractmethod s(位于{的装饰器) {1}}):

abc

从实例化中定义了禁止from abc import ABC, abstractmethod class List(ABC, Block): @abstractmethod def size(self): return 0 的ABC。

答案 2 :(得分:0)

您的List类应该将ABCMeta作为元类,并使init方法抽象化。

from abc import ABCMeta
class List(metaclass=ABCMeta):
    @abstractmethod
    __init__():
        pass

https://docs.python.org/3/library/abc.html

答案 3 :(得分:0)

“一个明显的”方法是使用ABCMeta并将某些方法标记为抽象,如其他答案所述。

但是如果在你的情况下你没有必须以强制方式覆盖的一组方法(让我们假设你的__init__在某些情况下是可重用的,而其他的列表方法也是如此) :

在这种情况下,您可以创建一个__new__方法来检查被证实的clas是否是自己的类,然后引发。要做到这一点,你必须使用仅在Python文档的角落记录的魔法__class__变量 - 如果你在任何方法体中使用__class__变量,它将自动获取值在运行时声明它的类。它是Python 3的无参数super机制的一部分。

因此:

class List(Block):
    def __new__(cls, *args, **kw):
        if cls is __class__:
            raise TypeError(cls.__name__ + " can't be directly instantiated")
        return super().__new__(cls, *args, **kw)

顺便说一下,如果您的模式允许,应该优先选择ABCMeta抽象方法。请注意,如果您的类使用自定义元类,它也会与ABCMeta冲突 - 所以您可能也需要求助于此

(如果您不进一步自定义__new__,那么最好不要在args方法上传kw__new__上游:Python的{{1}如果object.__new__已定义但__init__不在子类中,则忽略额外的args - 但如果两者都定义则会引发错误)