繁体   English   中英

Python - 动态 class 注册与 inheritance 从抽象基础 ZA2F2ED4F8EBC2CBB4C21A29DC40AB1

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM