从基础 class 的构造函数中的同一子模块导入其他子 classes

Import other child classes from same submodule within constructor of base class

给定以下文件夹结构:

train
|__base
|  |__model.py
|  |__layer.py
|
|__nb
|  |__model.py
|  |__layer.py
|
|__norm
|  |__model.py
|  |__layer.py

nb 和 norm 分别包含特定于 nb 和范数分布的模型和层。 这两个文件夹中的 类 ModelLayer 是基本文件夹中相应 类 的子项。 比方说,Model 的实例包含 Layer 的实例,而 model.layer 当然必须来自同一文件夹。 但是我需要从 base.model.py 调用模型的超级构造函数并在那里创建分布特定层。

我可以做某事。在基础模型构造函数中像这样:

__init__(self, distribution, **kwargs):
    if distribution == 'nb':
        from nb.layer import Layer
    elif distribution == 'norm':
        from norm.layer import Layer
    else:
        assert False, "Unrecognized distribution."
    self.layer = Layer()

现在我需要了解基本模型中的所有分布并对传递的分布字符串进行硬编码。但是我的工具需要可扩展,因此我不知道将来会添加哪些额外的发行版。我想找到一个奇特的解决方案,使它能够自动检测必须从哪个子文件夹导入,基于从哪个子模型调用了基本模型构造函数(即,如果创建了标准模型,则基本模型也应该导入范数层,而不是nb层)。

有什么办法可以绕过它吗? 完美的解决方案无需将 distribution 等任何其他参数传递给基本构造函数即可工作。 但是即使有必要传递 distribution,是否有可能以某种方式将正确的路径传递到 nb/norm 子文件夹并执行某项操作。喜欢 from <distribution>.layer import Layer?

一种方法是使用 importlib.import_module:

from importlib import import_module


class Model:
    __init__(self, distribution_module: str):
        layers = import_module(name='...' + distribution_module + '.layers', package=__name__)
        self.layer = layers.Layer()

distribution_module 必须以子模块命名,(即本例中的 'norm' 或 'nb')。根据文件夹结构,相对于 package 的相对路径必须附加点(即在本例中为“...”,因为 __name__ 是 'train.base.model')。 如果提供绝对路径,也可以丢弃 package arg。

查看文档:https://docs.python.org/3/library/importlib.html#importlib.import_module