动态导入所有子类

时间:2018-04-30 09:59:38

标签: python python-3.x

我有一个带有许多派生类的抽象基类。我试图通过将所有派生类放在与基类相同的文件中来实现我将获得的相同行为,即如果我的类是BaseDerivedA,{{1文件DerivedB中的DerivedC,我可以写入另一个文件

myclass.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(),因为我无法弄清楚如何(或者它是否可能)使用importlib来实现等效的myclass.derived_c.DerivedC()语句。

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

编辑:Dynamic module import in Python的解决方案不提供自动将所有模块中的类导入到包名称空间的方法。

1 个答案:

答案 0 :(得分:1)

我不得不在一段时间内做出类似的东西,但在我的情况下,我必须动态创建一个包含特定包中基类的所有子类的列表,以防万一你发现它很有用:

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

    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__()
    
  5. 现在subclasses是一个列表,其中包含从Base派生的所有类。