如何在asdict中获取@property方法?

10

我有一些类似于:

from attr import attrs, attrib

@attrs
class Foo():
    max_count = attrib()
    @property
    def get_max_plus_one(self):
         return self.max_count + 1

现在当我执行:

f = Foo(max_count=2)
f.get_max_plus_one =>3

我想将这个转换为字典:

{'max_count':2, 'get_max_plus_one': 3}

当我使用attr.asdict(f)时,我得不到@property。 我只得到{'max_count':2}

如何最简单地实现上述目标?

4个回答

3

通常情况下,您需要遍历属性并检查property的实例,然后使用实例调用属性的__get__方法。因此,代码大致如下:

In [16]: class A:
    ...:     @property
    ...:     def x(self):
    ...:         return 42
    ...:     @property
    ...:     def y(self):
    ...:         return 'foo'
    ...:

In [17]: a = A()

In [18]: vars(a)
Out[18]: {}

In [19]: a.x
Out[19]: 42

In [20]: a.y
Out[20]: 'foo'

In [21]: {n:p.__get__(a) for n, p in vars(A).items() if isinstance(p, property)}
Out[21]: {'x': 42, 'y': 'foo'}

3

1
针对此情况,您可以在对象上使用dir,并仅获取不以__开头的属性,即忽略魔术方法:
In [496]: class Foo():
     ...:     def __init__(self):
     ...:         self.max_count = 2
     ...:     @property
     ...:     def get_max_plus_one(self):
     ...:          return self.max_count + 1
     ...:     

In [497]: f = Foo()

In [498]: {prop: getattr(f, prop) for prop in dir(f) if not prop.startswith('__')}
Out[498]: {'get_max_plus_one': 3, 'max_count': 2}

为了处理不以__开头的常规方法,您可以添加一个callable测试:

In [521]: class Foo():
     ...:     def __init__(self):
     ...:         self.max_count = 2
     ...:     @property
     ...:     def get_max_plus_one(self):
     ...:          return self.max_count + 1
     ...:     def spam(self):
     ...:         return 10
     ...:     

In [522]: f = Foo()

In [523]: {prop: getattr(f, prop) for prop in dir(f) if not (prop.startswith('__') or callable(getattr(Foo, prop, None)))}
Out[523]: {'get_max_plus_one': 3, 'max_count': 2}

Foo类中的所有方法以及Foo类方法解析顺序(MRO)中的所有方法怎么办?但在这里使用getattr显然更合适。 - juanpa.arrivillaga
@juanpa.arrivillaga 这很快变得棘手起来,我喜欢你的通用方法,但我的解决方案有点具体化。 - heemayl
我的意思只是,如果Foo有任何方法,比如Foo.doStuff,你最终会得到一堆绑定的方法。 - juanpa.arrivillaga
@juanpa.arrivillaga 好的,编辑完毕。 - heemayl
这两个代码片段产生相同的结果 - 那么添加“callable”测试的意义是什么? - martineau

0
如果你定义了:

import attr

def attr2dict(inst):
    dic = attr.asdict(inst)
    dic.update({n: p.__get__(inst) for n, p in vars(type(inst)).items() if isinstance(p, property)})
    return dic

然后你就得到了你想要的东西:

>>> attr2dict(f)
{'max_count': 2, 'get_max_plus_one': 3}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接