[英]Python - Dynamic class registration with inheritance from abstract base class
我想用动态的模块化阅读器对象实现一个通用的标准化数据接口。 目前我在工厂 class DataFrameInterface
,它通过装饰器@DataFrameInterface.register_reader()
注册 Reader 对象。
到目前为止效果很好。 我现在想要实现的是,实际阅读器的装饰器或注册仅在抽象基础 class BasicReader(ABC)
中定义,并由特定的阅读器实现继承。 这里的问题是不能简单地继承装饰器。
简而言之,我不想在每个阅读器 class 之前手动放置装饰器,我希望已经在抽象 class BasicReader
的 inheritance 处完成这项工作。
为了使我的问题更清楚一点,您可以在下面找到一个更详细的示例(*删除了一些文档字符串和功能代码,以使列表更具可读性和紧凑性)。
提前感谢任何提示和建议。
# Import used modules
from abc import ABC, abstractmethod
from pathlib import Path
class DataFrameInterface(object):
"""Basic Interface Class."""
readers = []
"""List of registered reader objects"""
def __new__(cls, filepath, rbit="r", **kwargs):
filepath = Path(filepath)
# Perform file checks for each registered reader
for reader in cls.readers:
if reader._check(filepath):
return reader(filepath, rbit=rbit, **kwargs)
# If no suitable reader is implemented, raise exception
_msg = "The input must be a VTK or HDF data set and not {}.".format(filepath.suffix)
raise NotImplementedError(_msg)
@classmethod
def register_reader(cls):
"""
Register reader as subclass of DataFrameInterface.
For a reader to become available, the class object of the reader must
have the active decorator @DataFrameInterface.register_reader().
"""
def decorator(subclass):
cls.readers.append(subclass)
return subclass
return decorator
class BasicReader(ABC):
"""An abstract base class for constructing a common reader interface."""
def __init__(self, filename, rbit="r", **kwargs):
"""Initialize the reader object."""
self.rbit = rbit
self.attrs, self.dataframe = self._load(filename, rbit)
return
@abstractmethod
def get_timeSteps(self):
pass
@abstractmethod
def get_mesh(self):
pass
def get_constants(self):
pass
@abstractmethod
def get_data(self):
pass
@abstractmethod
def get_mesh(self):
pass
@abstractmethod
def _check(filepath):
return False
@DataFrameInterface.register_reader()
class HDFReader(BasicReader):
"""A simple reader for hdf datasets."""
@staticmethod
def _check(filename):
return filename.suffix == ".h5"
@staticmethod
def _load(filename, rbit):
pass
def get_timeSteps(self, dname="times", dfrom="constants"):
pass
def get_constants(self, arr_name, index=None, dtype="index"):
pass
def get_data(self, arr_name, timeSteps=None, dtype="point_data"):
pass
def get_mesh(self, time=None, mtype="constant"):
pass
# For testing purpose
if __name__ == "__main__":
data = DataFrameInterface("filename.h5")
正如我刚刚发现的那样,由于 Python 3.6 存在__init_subclass__
方法。 此方法在 inheritance 期间和 class 初始化之前调用。 幸运的是,3.6 版是该项目的最低要求。 我没有意识到这一点,偶然发现了自己。 所以这是我的问题的解决方案。
解决方案很简单,可以轻松处理。 只有这段代码必须被添加到继承自的超类(BasicReader)中,其他一切都会自动发生,无需额外的装饰器:
def __init_subclass__(cls):
DataFrameInterface.register_reader(cls)
return
接下来必须修改register_reader
方法:
@classmethod
def register_reader(cls1, cls):
"""Register reader as subclass of DataFrameInterface."""
cls1.readers.append(cls)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.