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

Posted

技术标签:

【中文标题】如何在 asdict 中获取@property 方法?【英文标题】:How to get @property methods in asdict? 【发布时间】:2019-01-14 23:06:46 【问题描述】:

我有类似的东西:

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.

实现上述目标的最简洁方法是什么?

【问题讨论】:

【参考方案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 这很快就会变得棘手,我喜欢你的通用方法,但我的解决方案有点具体。 好吧,我的意思很简单,如果Foo 有任何方法,比如Foo.doStuff,你最终会得到一堆绑定方法。 @juanpa.arrivillaga 够公平的。已编辑。 两个 sn-ps 产生相同的结果 — 那么添加 callable 测试有什么意义呢?【参考方案2】:

通常,您必须遍历 classes 属性并检查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】:

恐怕attrs 目前不支持。您可能想关注/评论https://github.com/python-attrs/attrs/issues/353,这可能最终会为您提供您想要的。

【讨论】:

【参考方案4】:

如果你定义:

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

【讨论】:

以上是关于如何在 asdict 中获取@property 方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何估计pyspark中的数据框实际大小?

如何在 C# 中获取 PSObject.Properties 的 ScriptProperty 值?

如何从跟踪器响应中获取对等方的 IP 和端口

如何在C#中获取PSObject.Properties的ScriptProperty值?

如何在 API 网关上的 cognito 授权方保护的 lambda 函数中获取 AWS Cognito 用户数据

如何在泛型类中获取Property和Value?