在给定的 Python 文件中获取 类 的列表

Getting the list of classes in a given Python file

我的目标是获取给定 Python 文件中定义的列表 类。

在此link之后,我实施了以下内容:

文件b.py:

import imp
import inspect

module = imp.load_source("__inspected__", './a.py')
class_members = inspect.getmembers(module, inspect.isclass)
for cls in class_members:
    class_name, class_obj = cls
    member = cls[1]
    print(class_name)

文件a.py:

from c import CClass


class MyClass:
    name = 'Edgar'

    def foo(self, x):
        print(x)

文件c.py:

c_var = 2

class CClass:
   name = 'Anna'

这个实现有两个问题。 首先,作为 is mentioned in the post,导入模块的 类 也被打印出来。我不明白如何排除它们 其次,看起来 imp 文件已贬值以支持 importlib,但该文档似乎很粗略。而且我不知道如何重构我的解决方案。有什么提示吗?

所以要像使用 imp 一样使用 importlib,您可以看看这个:Python 3.4: How to import a module given the full path? 你会得到如下内容:

import importlib.machinery
import inspect

module = importlib.machinery.SourceFileLoader("a", './a.py').load_module()
class_members = inspect.getmembers(module, inspect.isclass)

解决方案 #1:在抽象语法树 (AST) 中查找 class 语句。

基本上你可以解析文件,这样你就可以获得 class 声明语句。

import ast

def get_classes(path):
    with open(path) as fh:        
       root = ast.parse(fh.read(), path)
    classes = []
    for node in ast.iter_child_nodes(root):
        if isinstance(node, ast.ClassDef):
            classes.append(node.name)
        else: 
            continue
    return classes
    
for c in get_classes('a.py'):
    print(c)

解决方案 #2:查看导入并忽略 import from 语句。

这更符合您当前的方法,但有点简陋。 您可以查找由您正在查看的文件导入的内容,并 select 从语句 (Python easy way to read all import statements from py module) 中导出导入内容,并确保导入的内容中的 none 稍后显示:

import ast
from collections import namedtuple

Import = namedtuple("Import", ["module", "name", "alias"])

def get_imports(path):
    with open(path) as fh:        
       root = ast.parse(fh.read(), path)

    for node in ast.iter_child_nodes(root):
        if isinstance(node, ast.Import):
            # We ignore direct imports
            continue
        elif isinstance(node, ast.ImportFrom):  
            module = node.module.split('.')
        else:
            continue
        for n in node.names:
            yield Import(module, n.name.split('.'), n.asname)

imported = set()
for imp in get_imports('a.py'):
    imported_classes.add(imp.name[0] if not imp.alias else imp.alias)

那你就可以过滤掉你看到的导入的东西了

for c in class_members:
    class_name, class_obj = c
    member = c[1]
    if class_name not in imported:
        print(class_name)

请注意,这目前无法区分导入的 classes 和导入的函数,但目前应该可以使用。