如何使用反射或解析读取Python类中声明成员的顺序(禁止元类替换)?

Cha*_*eon 2 python reflection class python-2.7

避免太快/无效重复标记的重要注意事项 - 请在回答前阅读。

不要建议任何更改原始类代码的解决方案- 不允许更改代码反射和解析。

  1. 如何按照声明的顺序读取类属性?是解决方案 - 它需要替换所有类中的元类并增加开销 - 绝对不是反射使用。

  2. 考虑到我不能或不想更改代码来扫描类成员顺序。类可以具有或已经具有未知的元类 - 不可能无缘无故地添加元类或增加性能开销。

  3. 只能使用反射或者解析文件。


我想避免编写解析器并按声明顺序读取类属性。

如何在 Python 中使用反射(和简单的解析)?

让我举一些例子:

class A(object):
  b = 1
  a = 1
  c = 1
Run Code Online (Sandbox Code Playgroud)

dir(A)给出字母顺序,但要求是声明顺序。如何做到这一点 - 请帮忙?

Mar*_*ers 5

你必须求助于解析。您不需要在这里编写解析器;该ast模块可以为您完成此操作。

使用 解析源代码ast.parse(),然后遍历生成的树:

class ClassOrder(ast.NodeVisitor):
    identifiers = None
    def visit_ClassDef(self, node):
        self.identifiers = []
        for child in node.body:
            if isinstance(child, ast.Assign):
                for target in child.targets:
                    self.visit(target)
            elif isinstance(child, ast.FunctionDef):
                self.identifiers.append(child.name)
    def visit_Name(self, node):
        if self.identifiers is not None:
            self.identifiers.append(node.id)

tree = ast.parse(sourcecode)
order = ClassOrder()
order.visit(tree)
print order.identifiers
Run Code Online (Sandbox Code Playgroud)

打印出所有类定义中赋值和方法的顺序。

演示:

>>> sourcecode = '''\
... class A(object):
...   b = 1
...   a = 1
...   c = 1
... '''
>>> tree = ast.parse(sourcecode)
>>> order = ClassOrder()
>>> order.visit(tree)
>>> print order.identifiers
['b', 'a', 'c']
>>> tree = ast.parse(inspect.getsource(ast.NodeVisitor))
>>> order = ClassOrder()
>>> order.visit(tree)
>>> print order.identifiers
['visit', 'generic_visit']
Run Code Online (Sandbox Code Playgroud)

捆绑为一个函数,使用inspect.getsource()

import inspect

def get_identifiers(obj):
    source = inspect.getsource(obj)
    tree = ast.parse(source)
    order = ClassOrder()
    order.visit(tree)
    return order.identifiers
Run Code Online (Sandbox Code Playgroud)

inspect.getsource()可以处理源可用的任何对象。对于类,它将提取定义该类的源块(如果可用)。