首页 > 解决方案 > 动态导入所有子类

问题描述

我有一个带有许多派生类的抽象基类。我试图通过将所有派生类与基类放在同一个文件中来实现相同的行为,即如果我的类是Base, DerivedA, DerivedB,DerivedCmyclass.py我可以写在另一个文件中的文件中

import myclass
a = myclass.DerivedA()
b = myclass.DerivedB()
c = myclass.DerivedC()

但是每个派生类都在自己的文件中。这必须是动态的,即这样我可以删除derived_c.py,并且一切仍然有效,除了现在我不能再调用myclass.DerivedC,或者如果我添加一个derived_d.py,我可以在不触及的情况下使用它,__init__.py所以简单地使用from derived_c import DerivedC不是一个选项。

我已经尝试将它们全部放在一个子目录中,并在该目录中__init__.py用于pkgutil.walk_packages()动态导入所有文件,但我无法让它们直接位于模块的命名空间中,即myclass.DerivedC()我必须调用myclass.derived_c.DerivedC(),因为我不能弄清楚如何(或者如果可能的话)使用 importlib 来实现from xyz import *语句的等价物。

关于如何实现这一目标的任何建议?谢谢!

编辑:Python中动态模块导入的解决方案没有提供将所有模块中的类自动导入包的命名空间的方法。

标签: pythonpython-3.x

解决方案


不久前我不得不做一些非常相似的事情,但就我而言,我必须动态地创建一个列表,其中包含特定包中基类的所有子类,所以如果你发现它有用:

  1. 创建一个包含您的类和所有子类my_classes的所有文件的包。Base您应该在每个文件中只包含一个类。
  2. __all__适当设置__init__.py以导入除(来自this answer.py )之外的所有文件:__init__.py

    from os import listdir
    from os.path import dirname, basename
    
    __all__ = [basename(f)[:-3] for f in listdir(dirname(__file__)) if f[-3:] == ".py" and not f.endswith("__init__.py")]
    
  3. 使用 导入您的类from my_classes import *,因为我们的自定义__all__my_classes包内的所有类添加到命名空间。

  4. 但是,这还不允许我们直接访问子类。您必须在主脚本中像这样访问它们:

    from my_classes import *
    from my_classes.base import Base
    
    subclasses = Base.__subclasses__()
    

现在subclasses是一个列表,其中包含所有派生自 的类Base


推荐阅读