递归遍历在运行时一个Python继承树

问题描述 投票:8回答:3

我用Python写一些序列化/反序列化的代码,将读/写一些JSON的继承层次。确切的组合物将不被知道,直到该请求以发送。

所以,我认为在优雅的解决方案,以递归内省Python类层次结构来发射,然后在回来的路上了通过树,在Python基本类型安装正确的价值观。

E.g.,

A
|
|\
| \
B  C

如果我把我的“内省”常规上B,它应该返回一个包含所有A的变量,他们的价值观,以及B的变量和它们的值的映射的字典。

目前的情况是,我可以期待通过B.__slots__B.__dict__,但我只能从那里撤出B的变量名。

我怎么只给B中的__slots__ / A的__dict__,? (或C)。

我知道,Python不直接支持铸造像C ++和它的后代做 -

python reflection introspection
3个回答
12
投票

您可以尝试使用type.mro()方法,找对方法解析顺序。

class A(object):
        pass

class B(A):
        pass

class C(A):
        pass

a = A()
b = B()
c = C()

>>> type.mro(type(b))
[<class '__main__.B'>, <class '__main__.A'>, <type 'object'>]
>>> type.mro(type(c))
[<class '__main__.C'>, <class '__main__.A'>, <type 'object'>]

要么

>>> type(b).mro()

编辑:我想你想要做这样的事情...

>>> A = type("A", (object,), {'a':'A var'})  # create class A
>>> B = type("B", (A,), {'b':'B var'})       # create class B
>>> myvar = B()

def getvars(obj):
    ''' return dict where key/value is attribute-name/class-name '''
    retval = dict()
    for i in type(obj).mro():
        for k in i.__dict__:
            if not k.startswith('_'):
                retval[k] = i.__name__
    return retval

>>> getvars(myvar)
{'a': 'A', 'b': 'B'}

>>> for i in getvars(myvar):
    print getattr(myvar, i)   # or use setattr to modify the attribute value

A Var
B Var

2
投票

也许你可以澄清你在找什么远一点?

目前您的描述完全不描述了Python。让我们假设你的榜样A,B和C是类的名称:

class A(object) :
...     def __init__(self) :
...             self.x = 1
class B(A) :
...     def __init__(self) :
...             A.__init__(self)
...             self.y = 1

然后,运行实例可以被创建为:

b = B()

如果你看一下运行时对象的字典那么它有它自己的变量和属于它的父类变量之间没有区别。因此,例如:DIR(b)中

[ ... snip lots of double-underscores ... , 'x', 'y']

所以直接回答你的问题是,它像了,但我怀疑是不是对你非常有帮助。什么不出来的方法,因为它们是在类的命名空间的条目,而变量是在对象的命名空间。如果你想找到在超方法然后使用MRO()调用如刚才的答复描述,然后通过在列表中类的命名空间看看。

当我四处寻找简单的方法做的JSON序列我发现了一些有趣的东西泡菜模块中。一个建议是,你可能要腌制/ unpickle的对象,而不是写自己的遍历hieracrchy。咸菜输出是一个ASCII流,可能会更容易为你来转换来回JSON。有在PEP 307一些出发点。

另一个建议是看看该__reduce__方法,尝试在要连载,因为它可能是你在找什么对象。


0
投票

如果你只需要一棵树(不是菱形继承),有一个简单的方法来做到这一点。通过分支[object, [children]]的嵌套列表代表树树叶[object, [[]]]

然后,通过定义递归函数:

def classTree(cls): # return all subclasses in form of a tree (nested list)
    return [cls, [[b for c in cls.__subclasses__() for b in classTree(c)]]]

你可以继承树:

class A():
    pass
class B(A):
    pass
class C(B):
    pass
class D(C):
    pass
class E(B):
    pass

>>> classTree(A)
[<class 'A'>, [[<class 'B'>, [[<class 'C'>, [[<class 'D'>, [[]]]], <class 'E'>, [[]]]]]]]

这是很容易,因为序列化这只是一个列表。如果你只想要名,由cls更换cls.__name__

对于反序列化,你必须让你的类从背课文。如果你想为这更多的帮助,请提供您的问题的细节。

© www.soinside.com 2019 - 2024. All rights reserved.