【问题标题】:Dynamically import all subclasses动态导入所有子类
【发布时间】:2018-04-30 09:59:38
【问题描述】:

我有一个带有许多派生类的抽象基类。我试图通过将所有派生类与基类放在同一个文件中来实现相同的行为,即如果我的类是BaseDerivedADerivedBDerivedC 在文件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() 我必须打电话给myclass.derived_c.DerivedC(),因为我不知道如何(或是否可能)使用 importlib 来实现与 from xyz import * 语句等效的操作。

对我如何实现这一点有什么建议吗?谢谢!

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

【问题讨论】:

标签: python python-3.x


【解决方案1】:

前段时间我不得不做一些非常相似的事情,但就我而言,我必须动态地创建一个列表,其中包含来自特定包中基类的所有子类,因此以防万一你觉得它有用:

  1. 创建一个my_classes 包,其中包含Base 类和所有子类的所有文件。您应该在每个文件中只包含一个类。
  2. __init__.py 中适当设置__all__ 以导入除__init__.py 之外的所有.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__()
    

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

【讨论】:

  • 谢谢,不幸的是,这不是我想要的,但在其他场合可能会派上用场。
  • @JohnO 从我链接的答案中查看问题,您可能会在那里找到有用的东西
  • 我在您链接的问题中的一个问题中发现了一些东西,特别是stackoverflow.com/questions/14426574/…。但是需要注意的是,DerivedA()derived_a.DerivedA() 现在都可以在包命名空间中使用。有什么想法吗?
  • 谢谢,这个解决方案非常适合我想要做的事情
  • 这也非常适合我想要做的事情。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-12
  • 1970-01-01
  • 2019-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-06
相关资源
最近更新 更多