您知道是否有一个内置函数可以从任意对象构建字典吗?我想这样做:

>>> class Foo:
...     bar = 'hello'
...     baz = 'world'
...
>>> f = Foo()
>>> props(f)
{ 'bar' : 'hello', 'baz' : 'world' }

注意:它不应该包括方法。只有字段。


当前回答

内置的dir会给你所有对象的属性,包括特殊的方法,如__str__, __dict__和一大堆你可能不想要的其他方法。但是你可以这样做:

>>> class Foo(object):
...     bar = 'hello'
...     baz = 'world'
...
>>> f = Foo()
>>> [name for name in dir(f) if not name.startswith('__')]
[ 'bar', 'baz' ]
>>> dict((name, getattr(f, name)) for name in dir(f) if not name.startswith('__')) 
{ 'bar': 'hello', 'baz': 'world' }

所以可以扩展它,只返回数据属性,而不返回方法,通过定义你的props函数:

import inspect

def props(obj):
    pr = {}
    for name in dir(obj):
        value = getattr(obj, name)
        if not name.startswith('__') and not inspect.ismethod(value):
            pr[name] = value
    return pr

其他回答

Dataclass(来自Python 3.7)是另一个可用于将类属性转换为dict的选项。Asdict可以与数据类对象一起使用 为了转换。

例子:

@dataclass
class Point:
   x: int
   y: int

p = Point(10, 20)
asdict(p) # it returns {'x': 10, 'y': 20}

Vars()很棒,但不适用于对象的嵌套对象

将对象的嵌套对象转换为dict:

def to_dict(self):
    return json.loads(json.dumps(self, default=lambda o: o.__dict__))

在2021年,对于嵌套对象/dicts/json使用pydantic BaseModel -将嵌套dicts和嵌套json对象转换为python对象和json,反之亦然:

https://pydantic-docs.helpmanual.io/usage/models/

>>> class Foo(BaseModel):
...     count: int
...     size: float = None
... 
>>> 
>>> class Bar(BaseModel):
...     apple = 'x'
...     banana = 'y'
... 
>>> 
>>> class Spam(BaseModel):
...     foo: Foo
...     bars: List[Bar]
... 
>>> 
>>> m = Spam(foo={'count': 4}, bars=[{'apple': 'x1'}, {'apple': 'x2'}])

对象to dict

>>> print(m.dict())
{'foo': {'count': 4, 'size': None}, 'bars': [{'apple': 'x1', 'banana': 'y'}, {'apple': 'x2', 'banana': 'y'}]}

对象转换为JSON

>>> print(m.json())
{"foo": {"count": 4, "size": null}, "bars": [{"apple": "x1", "banana": "y"}, {"apple": "x2", "banana": "y"}]}

反对的词典

>>> spam = Spam.parse_obj({'foo': {'count': 4, 'size': None}, 'bars': [{'apple': 'x1', 'banana': 'y'}, {'apple': 'x2', 'banana': 'y2'}]})
>>> spam
Spam(foo=Foo(count=4, size=None), bars=[Bar(apple='x1', banana='y'), Bar(apple='x2', banana='y2')])

JSON到对象

>>> spam = Spam.parse_raw('{"foo": {"count": 4, "size": null}, "bars": [{"apple": "x1", "banana": "y"}, {"apple": "x2", "banana": "y"}]}')
>>> spam
Spam(foo=Foo(count=4, size=None), bars=[Bar(apple='x1', banana='y'), Bar(apple='x2', banana='y')])

我认为最简单的方法是为类创建一个getitem属性。如果需要写入对象,可以创建自定义setattr。下面是一个getitem的例子:

class A(object):
    def __init__(self):
        self.b = 1
        self.c = 2
    def __getitem__(self, item):
        return self.__dict__[item]

# Usage: 
a = A()
a.__getitem__('b')  # Outputs 1
a.__dict__  # Outputs {'c': 2, 'b': 1}
vars(a)  # Outputs {'c': 2, 'b': 1}

Dict将对象属性生成到字典中,可以使用字典对象获取所需的项。

回答晚了,但为了完整性和谷歌人的利益:

def props(x):
    return dict((key, getattr(x, key)) for key in dir(x) if key not in dir(x.__class__))

这将不会显示类中定义的方法,但仍然会显示字段,包括那些分配给lambdas的字段或那些以双下划线开头的字段。