列出目录中的类 (Python)

发布于 2024-09-08 08:35:07 字数 442 浏览 2 评论 0原文

我正在开发一个 Python 2.6 包,在其中我想获取某个目录(包内)中所有类的列表,以便对类对象执行内省。

具体来说,如果包含当前正在执行的模块的目录有一个名为“foobar”的子目录,并且“foobar”包含指定 class Foo(MyBase)class Bar(MyBase)< 的 .py 文件/code> 和 class Bar2,我想获取继承自 MyBase 的类对象的引用列表,即 Foo 和 < code>Bar,但不是 Bar2

我不确定这个任务是否真的需要涉及文件系统的任何处理,或者子目录中的模块是否自动加载并且只需要通过某种方式内省列出。请问这里有什么想法吗?非常感谢示例代码,因为我对 Python 还很陌生,尤其是内省。

I'm developing a Python 2.6 package in which I would like to fetch a list of all classes in a certain directory (within the package) in order to then perform introspection on the class objects.

Specifically, if the directory containing the currently executing module has a sub-dir called 'foobar' and 'foobar' contains .py files specifying class Foo(MyBase), class Bar(MyBase), and class Bar2, I want to obtain a list of references to the class objects that inherit from MyBase, i.e. Foo and Bar, but not Bar2.

I'm not sure if this task actually need involve any dealing with the filesystem or if the modules in the sub-dir are automatically loaded and just need to be listed via introspection somehow. Any ideas here please? Example code is much appreciated, since I'm pretty new to Python, in particular introspection.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

倒带 2024-09-15 08:35:07

模块永远不会自动加载,但应该很容易迭代目录中的模块并使用 __import__ 内置函数加载它们:

import os
from glob import glob
for file in glob(os.path.join(os.path.dirname(os.path.abspath(__file__))), "*.py"):
    name = os.path.splitext(os.path.basename(file))[0]
    # add package prefix to name, if required
    module = __import__(name)
    for member in dir(module):
        # do something with the member named ``member``

Modules are never loaded automatically, but it should be easy to iterate over the modules in the directory and load them with the __import__ builtin function:

import os
from glob import glob
for file in glob(os.path.join(os.path.dirname(os.path.abspath(__file__))), "*.py"):
    name = os.path.splitext(os.path.basename(file))[0]
    # add package prefix to name, if required
    module = __import__(name)
    for member in dir(module):
        # do something with the member named ``member``
梦境 2024-09-15 08:35:07

我想做同样的事情,这就是我最终的结果:

import glob
import importlib
import inspect
import os

current_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)))
current_module_name = os.path.splitext(os.path.basename(current_dir))[0]
for file in glob.glob(current_dir + "/*.py"):
     name = os.path.splitext(os.path.basename(file))[0]

     # Ignore __ files
     if name.startswith("__"):
         continue
     module = importlib.import_module("." + name,package=current_module_name)

     for member in dir(module):
         handler_class = getattr(module, member)

         if handler_class and inspect.isclass(handler_class):
             print member

希望它有帮助..

I wanted to do the same thing, this is what I ended up with:

import glob
import importlib
import inspect
import os

current_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)))
current_module_name = os.path.splitext(os.path.basename(current_dir))[0]
for file in glob.glob(current_dir + "/*.py"):
     name = os.path.splitext(os.path.basename(file))[0]

     # Ignore __ files
     if name.startswith("__"):
         continue
     module = importlib.import_module("." + name,package=current_module_name)

     for member in dir(module):
         handler_class = getattr(module, member)

         if handler_class and inspect.isclass(handler_class):
             print member

Hope it helps..

醉南桥 2024-09-15 08:35:07

选项 1:使用 -r 参数 grep for "^class (\a\w+)\(Myclass" 正则表达式。

选项 2:将目录作为包(创建一个空的 __init__.py 文件),导入它并递归地迭代其成员:

import mymodule
def itermodule(mod):
    for member in dir(mymod):
        ...

itermodule(mymodule)

Option 1: grep for "^class (\a\w+)\(Myclass" regexp with -r parameter.

Option 2: make the directory a package (create an empty __init__.py file), import it and iterate recursively over its members:

import mymodule
def itermodule(mod):
    for member in dir(mymod):
        ...

itermodule(mymodule)
2024-09-15 08:35:07

我自己处理过,这是我的版本(分叉@krakover片段):

  • 迭代目录并导入放置在那里的每个脚本
    • 过滤掉抽象类
    • 过滤掉不继承基类的类
    • 每个迭代类的新实例(如果您发现它没有用,请更改它)

import importlib
import inspect
import os
import glob


def import_plugins(plugins_package_directory_path, base_class=None, create_instance=True, filter_abstract=True):

    plugins_package_name = os.path.basename(plugins_package_directory_path)

    # -----------------------------
    # Iterate all python files within that directory
    plugin_file_paths = glob.glob(os.path.join(plugins_package_directory_path, "*.py"))
    for plugin_file_path in plugin_file_paths:
        plugin_file_name = os.path.basename(plugin_file_path)

        module_name = os.path.splitext(plugin_file_name)[0]

        if module_name.startswith("__"):
            continue

        # -----------------------------
        # Import python file

        module = importlib.import_module("." + module_name, package=plugins_package_name)

        # -----------------------------
        # Iterate items inside imported python file

        for item in dir(module):
            value = getattr(module, item)
            if not value:
                continue

            if not inspect.isclass(value):
                continue

            if filter_abstract and inspect.isabstract(value):
                continue

            if base_class is not None:
                if type(value) != type(base_class):
                    continue

            # -----------------------------
            # Instantiate / return type (depends on create_instance)

            yield value() if create_instance else value

用法:

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
plugins_directory_path = os.path.join(SCRIPT_DIR, 'plugins')
plugins = import_plugins(plugins_directory_path, base_class=BasePlugin)

for plugin in plugins:
    plugin.foo()
  • 假设有一个名为 plugins 包含 BasePlugin 类的实现

Dealt with it myself, this is my version (forked @krakover snippet):

  • Iterate directory and import each script placed there
    • Filter out abstract classes
    • Filter out classes that not inherit a base class
    • New instance for each iterated class (change it if you don't find it useful)

import importlib
import inspect
import os
import glob


def import_plugins(plugins_package_directory_path, base_class=None, create_instance=True, filter_abstract=True):

    plugins_package_name = os.path.basename(plugins_package_directory_path)

    # -----------------------------
    # Iterate all python files within that directory
    plugin_file_paths = glob.glob(os.path.join(plugins_package_directory_path, "*.py"))
    for plugin_file_path in plugin_file_paths:
        plugin_file_name = os.path.basename(plugin_file_path)

        module_name = os.path.splitext(plugin_file_name)[0]

        if module_name.startswith("__"):
            continue

        # -----------------------------
        # Import python file

        module = importlib.import_module("." + module_name, package=plugins_package_name)

        # -----------------------------
        # Iterate items inside imported python file

        for item in dir(module):
            value = getattr(module, item)
            if not value:
                continue

            if not inspect.isclass(value):
                continue

            if filter_abstract and inspect.isabstract(value):
                continue

            if base_class is not None:
                if type(value) != type(base_class):
                    continue

            # -----------------------------
            # Instantiate / return type (depends on create_instance)

            yield value() if create_instance else value

Usage:

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
plugins_directory_path = os.path.join(SCRIPT_DIR, 'plugins')
plugins = import_plugins(plugins_directory_path, base_class=BasePlugin)

for plugin in plugins:
    plugin.foo()
  • imagine there's a sub directory called plugins contains implementations of a BasePlugin class
浪漫之都 2024-09-15 08:35:07

在具有egrep的平台上:

from subprocess import Popen, PIPE
from re import search

def get_classes(directory):
    job = Popen(['egrep', '-ir', '--include=*.py', 'class ', str(directory), ], stdout=PIPE)
    fileout, fileerr = job.communicate()
    if fileerr:
        raise Exception(fileerr)
    while directory[-1] == '/':
        directory = directory[:-1]
    found = []
    for line in fileout.split('\n'):
        match = search('^([^:]+).py:\s*class\s*(\S+)\s*\((\S+)\):', line)
        if match:
            pypath = match.group(1).replace(directory, '').replace('/', '.')[1:]
            cls = match.group(2)
            parents = filter(lambda x: x.strip, match.group(3).split())
            found.append((pypath, cls, parents, ))
    return found

对于get_classes('.'),egrep返回类似以下内容:

./helpers/action.py:class Action(object):
./helpers/get_classes.py:    job = Popen(['egrep', '-ir', '--include=*.py', 'class ', str(directory), ], stdout=PIPE) # this is the get_classes script; not a valid result
./helpers/options.py:class Option(object):

它被转换为路径、类名和直接祖先的元组:

[('helpers.action', 'Action', ['object']), ('helpers.options', 'Option', ['object'])]

如果您只想要路径,那就是< code>[item[0] for get_classes('.')]。

On platforms that have egrep:

from subprocess import Popen, PIPE
from re import search

def get_classes(directory):
    job = Popen(['egrep', '-ir', '--include=*.py', 'class ', str(directory), ], stdout=PIPE)
    fileout, fileerr = job.communicate()
    if fileerr:
        raise Exception(fileerr)
    while directory[-1] == '/':
        directory = directory[:-1]
    found = []
    for line in fileout.split('\n'):
        match = search('^([^:]+).py:\s*class\s*(\S+)\s*\((\S+)\):', line)
        if match:
            pypath = match.group(1).replace(directory, '').replace('/', '.')[1:]
            cls = match.group(2)
            parents = filter(lambda x: x.strip, match.group(3).split())
            found.append((pypath, cls, parents, ))
    return found

For get_classes('.'), egrep returns something like:

./helpers/action.py:class Action(object):
./helpers/get_classes.py:    job = Popen(['egrep', '-ir', '--include=*.py', 'class ', str(directory), ], stdout=PIPE) # this is the get_classes script; not a valid result
./helpers/options.py:class Option(object):

which is converted into tuples of the path, class name and direct ancestors:

[('helpers.action', 'Action', ['object']), ('helpers.options', 'Option', ['object'])]

If you just want the paths, that's [item[0] for item in get_classes('.')].

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文