简体   繁体   English

从模块中获取类而无需实际运行文件

[英]Fetching classes from a module without actually having to run the file

Going on this question of mine , my goal now is to parse a Python file, and to继续我的这个问题,我现在的目标是解析一个 Python 文件,并

  1. Extract all classes提取所有类
  2. Extract the list of its attributes and list of bases classes提取其属性列表和基类列表

Without loading the file (running it).加载文件(运行它)。

Currently, I have this working code:目前,我有这个工作代码:

parser.py解析器.py

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)

File to be parsed:要解析的文件:

from c import CClass
    
class MyClass(UndefinedClass):
    name = 'Edgar'

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


def func():
    print('Hello')

The good part of this solution is that I get the list of class names even given that file a.py contains invalid python code.这个解决方案的好处是,即使给定文件 a.py 包含无效的 python 代码,我也能得到类名列表。 Looks like I have to dig deeper into AST module.看起来我必须更深入地研究 AST 模块。 Is there any way I can extract the list of class attributes and its base classes ?有什么办法可以提取类属性及其基类的列表吗?

You can use recursion to traverse the ast produced by ast.parse .您可以使用递归遍历ast.parse生成的ast The solution below performs this search not only in the main input file but in any subsequent imported files as well:下面的解决方案不仅在主输入文件中执行此搜索,而且还在任何后续导入的文件中执行此搜索:

import ast, importlib
class Parse:
   def __init__(self):
      self.c = {}
   def walk(self, tree, f = None):
      if isinstance(tree, ast.ClassDef):
         self.c[tree.name] = {'bases':[i.id for i in tree.bases], 'attrs':[]}
         for i in tree.body:
             self.walk(i, tree.name)
      elif isinstance(tree, (ast.ImportFrom, ast.Import)):
         for i in (k if isinstance((k:=getattr(tree, 'module', tree.names)), list) else [k]):
             with open(importlib.machinery.PathFinder().find_module(getattr(i, 'name', i)).get_filename()) as f:
                self.walk(ast.parse(f.read()))
      elif isinstance(tree, ast.Assign) and f is not None:
         self.c[f]['attrs'].append(tree.targets[0].id)
      else:
         for i in getattr(tree, '_fields', []):
            for j in (k if isinstance((k:=getattr(tree, i)), list) else [k]):
               self.walk(j, None)

Putting it all together with your two original files:将它们与您的两个原始文件放在一起:

File c.py:文件 c.py:

c_var = 2

class CClass:
   name = 'Anna'

File a.py:文件 a.py:

from c import CClass
    
class MyClass(UndefinedClass):
    name = 'Edgar'

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


def func():
    print('Hello')
p = Parse()
with open('a_mod_test.py') as f:
   p.walk(ast.parse(f.read()))

print(p.c)

Output:输出:

{'CClass': {'bases': [], 'attrs': ['name']}, 'MyClass': {'bases': ['UndefinedClass'], 'attrs': ['name']}}

A ClassDef node has a bases attribute which is a list of nodes representing the base classes for the class. ClassDef节点有一个bases属性,它是一个节点列表,表示该类的基类。 It also has a body attribute which is a list of nodes representing the body of the class definition.它还有一个body属性,它是一个代表类定义主体的节点列表。 I suppose you want the Assign nodes in the body, but maybe you mean something slightly different by class attributes.我想你想要正文中的Assign节点,但也许你的意思是类属性略有不同。

https://docs.python.org/3/library/ast.html#ast.ClassDef https://docs.python.org/3/library/ast.html#ast.ClassDef

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何从2个类继承而不必更改原始类? - How to inherit from 2 classes without having to change the original classes? 从模块访问变量,而无需在python中指定模块名称 - Accessing variables from module without having to specify module name in python 如何从Windows命令行运行python文件(.py)而不必先键入python? - How to run a python file (.py) from the windows command-line without having to type python first? 如何从我的 python 类创建一个可调用的函数,而不必在调用时运行整个文件? - How to make a call-able function from my python Class, without having to run the entire file if called? 使用re模块从python中的文本文件中获取数据 - Fetching data from a text file in python using re module 在不实际执行的情况下导入 python 模块 - Importing a python module without actually executing it 如何从一个模块导入类并初始化并在Django中运行 - how to import classes from one module and initialise and run it in django 如何修改和运行 my.py 文件中的一大段代码,而不必每次都读取整个.xlsx 文件? - How do I modify and run a chunk of code from my .py file without having to read the whole .xlsx file every time? 如何在不实际创建文件的情况下从变量或http URL获取文件对象? - How to obtain a file object from a variable or from http URL without actually creating a file? 从其他班级运行班级时遇到问题 - Having trouble running classes from other classes
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM