我想创建一个类层次结构,其中我有一个类Block
,可以自己实例化。然后我有一个继承自List
的类Block
并包含所有列表共有的方法,最后我有从{{1}继承的类OrderedList
,LableledList
等}。我希望人们能够实例化List
等,但不能OrderedList
。
换句话说,您可以实例化普通List
,并且可以实例化继承自Block
的{{1}}的{{1}},但您无法实例化OrderedList
。
Google的所有尝试都会导致抽象基类,但没有提供符合这种情况的例子,我在推断时遇到了麻烦。
答案 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
答案 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 - 但如果两者都定义则会引发错误)