【问题标题】:How to get all subclass of a given class in a directory with Python3?如何使用 Python3 在目录中获取给定类的所有子类?
【发布时间】:2023-04-01 20:17:01
【问题描述】:

我想要一个子类对象的列表,而不仅仅是它们的名称。

我是这样想的:

  • 首先,使用os.walk获取所有.py文件
  • 然后使用imp 模块导入所有这些文件(
  • 检查这些类是否是子类

目录结构:

├── src
│   ├── __init__.py 
│   └── connector.py
└── test_app
    ├── __init__.py
    └── test.py

connector.py代码:

import imp


class BaseModel(object):
    """which I wanna check it's subclass"""


class SomeClass(object):
    @classmethod
    def detect_all(cls, app_path=None):
        for path, subdirs, files in os.walk(app_path):
            for name in files:
                file_list.append(os.path.join(path, name)) if name.endswith('.py') and not name.startswith('_') else ''
        for file in file_list:
            imp.load_source(file.split('/')[0], file)
        print(cls.get_all_subclasses(BaseModel))

    @staticmethod
    def get_all_subclasses(cls):
        # argument cls is a target class
        all_subclasses = []

        for subclass in cls.__subclasses__():
            all_subclasses.append(subclass)
            all_subclasses.extend(SomeClass.get_all_subclasses(subclass))

test.py代码:

import os
import sys
sys.path.append('../')
sys.path.append('../src')

from src.connector import SomeClass, BaseModel

class User(BaseModel):
    pass

b = User()

current_dir = os.path.dirname(os.path.realpath(__file__))

print(SomeClass.detect_all(current_dir))

但是当我运行这个文件时,结果总是循环,最后给了我一个RecursionError: maximum recursion depth exceeded

如何满足我的需要,或如何修复此代码。

【问题讨论】:

    标签: python python-3.x python-module


    【解决方案1】:

    首先:Python 不是 Java。删除无用的 SomeClass 类,让这两个函数只是模块中的函数。这样做时,删除detect_all 的无用'cls' 参数。我在下面的回答假设了这种变化。

    由于缺少初始化file_list = [],因此发布的代码将无法运行。我假设它在运行时就在那里。

    我相信无限递归如下:test.py 调用detect_all(current_dir)current_dir 调用 os.walk(current_dir),它返回 'test.py'。然后它调用imp.load_source('test.py')test.py 然后(重新)调用detect_all(current_dir)。等等。

    imp 已被弃用,取而代之的是 importlib。当前的imp 章节没有提到load_source,但我认为它确实在加载源代码之前将'test' 添加到sys.modules。正常导入通过首先检查sys.modules 来避免无限递归,并且仅在首先将空模块添加到 sys.modules 之后才加载尚未存在的模块。

    你应该做什么:当你运行 test.py 时,'',代表目录test_app/,被添加到 sys.path 之前。因此,您可以按模块名称导入该目录中的模块。列出模块名称的mod_names。当 os.walk 找到 'xyz.py' 时,去掉 .py 扩展名。在子目录中递归时,在前面加上'subname.',这样你就可以得到一个正确的带点的模块名称,就像你在正常的导入语句中使用的那样。然后用

    替换imp循环
        for mod in mod_names:
            importlib.import_module(mod)
    

    我做了类似的事情来测试我正在编写的包中的所有模块。我避免使用排除列表(还包含一些其他模块)进行递归。但是,这应该不是必需的,因为 import_module 确实将条目添加到 sys.modules。

    【讨论】:

    • 谢谢。但我不知道 mod_names 和它们有多少,所以我不能在开头提供模块名称列表,这就是我想要实现的目标
    • 您仍然使用 os.walk 并在删除 '.py' 后从文件名中获取模块名称。您还必须使用子目录名称。
    猜你喜欢
    • 1970-01-01
    • 2011-02-01
    • 2023-03-17
    • 1970-01-01
    • 2010-10-04
    相关资源
    最近更新 更多