我想知道如何最好地在Python的抽象类层次结构上定义__subclasshook__
。假设我有一个接口,还有一个继承自这个接口的ABC。这样可以吗?
import abc
from typing import IO
class IFileHandler(metaclass=abc.ABCMeta):
def import(self) -> bytes:
raise NotImplementedError
def export(self) -> IO:
raise NotImplementedError
@classmethod
def __subclasshook__(cls, subclass):
return all((
hastattr(subclass, 'import'),
callable(getattr(subclass, 'import', None)),
hasattr(subclass, 'export'),
callable(getattr(subclass, 'export', None))
)) or NotImplemented
class FileBase(IFileHandler, metaclass=abc.ABCMeta):
def __init__(self):
...
def import(self):
...
def export(self):
raise NotImplementedError
def another_method(self):
...
@classmethod
def __subclasshook__(cls, subclass):
if super().__subclasshook(subclass) is NotImplemented:
return NotImplemented
return all((
hasattr(subclass, '__init__'),
callable(getattr(subclass, '__init__', None)),
hasattr(subclass, 'another_method'),
callable(getattr(subclass, 'another_method', None)),
)) or NotImplemented
class ConcreteFileClass(FileBase):
def export(self):
...
是否有一种更优雅的方式来调用超类'__subclasshook__
和处理其结果?我是不是完全找错了对象?任何见解将非常感激,谢谢!
您可以考虑使用abstractmethod
装饰器,而不是重新发明abc
的整个机制:
from abc import ABCMeta, abstractmethod
from typing import IO
class IFileHandler(metaclass=ABCMeta):
@abstractmethod
def import(self) -> bytes:
pass
@abstractmethod
def export(self) -> IO:
pass
class FileBase(IFileHandler):
@abstractmethod
def __init__(self):
pass
def import(self):
...
def export(self):
...
@abstractmethod
def another_method(self):
pass
您不需要显式地将metaclass
提供给FileBase
,因为继承已经处理了它。abstractmethod
不允许在没有具体实现的情况下实例化子类。与其在存根方法中引发NotImplementedError
,不如使用Ellipsis
(...
)或pass
。这样,子类将能够正确地调用super().whatever
而不会出现错误。