在循环中获取属性名称

1 投票
3 回答
3791 浏览
提问于 2025-04-16 19:12

我该如何获取一个对象的属性名称和属性值呢?我想把它转换成字典,这样我就可以方便地将这个对象转换成JSON格式。

代码:

class User:
    ...
    def to_dict( self ):
        dict = {}
        for key, value in filter( lambda aname: not aname.startswith('_'), dir(self) ):
            dict[key] = value
    return dict

错误:

too many values to unpack

使用:

user = User({
    's_email': 'bob@email.com',
    's_password': 'password',
})
user.to_dict()
# JSON Serialize

3 个回答

0

我可能漏掉了什么,但为什么不直接用 user.__dict__ 呢?

4

你会遇到这个错误是因为 filter( lambda aname: not aname.startswith('_'), dir(u) ) 返回的是一个只有单个项的列表,而你却试图同时取出两个值(for key, value)。使用 dir 而不是 __dict__ 的一个可能原因是你想要获取类的属性或者继承的属性。因为 __dict__ 只包含实例的属性,所以它找不到这些。

class Base(object):
    x = 1

class User(Base):
    y = 2
    def __init__(self, z):
        self.z = z

>>> u = User(3)

>>> u.__dict__
<<< {'z': 3}

如果你还是想用 dir,可以这样做:

def to_dict(self):
    d = {}
    for k, v in [(x, getattr(self, x)) for x in dir(self) if not x.startswith('_')]:
        if not hasattr(v, '__call__'): d[k] = v # skip methods
    return d

>>> u = User(3)

>>> u.to_dict()
<<< {'x': 1, 'y': 2, 'z': 3}

不过,明确地定义属性 就像这个回答中提到的那样,可能是最好的方法。

1

使用 self.__dict__。它是一个字典,表示这个对象的命名空间。

class User:
    ...
    def to_dict(self):
        return dict(
            [(k, v) for k, v in self.__dict__.iteritems() if not k.startswith('_')]
        )

注意,根据你的代码片段,.to_dict() 返回的字典会包含一个键 'to_dict',因为这个函数的名字没有以下划线开头。这可能是你发帖时的一个小错误。

如果你想在返回的字典中包含的属性列表比较小(而且变化不大),我建议你明确列出这些属性。

class User(object):
    data_attributes = ('s_email', 's_password')
    def to_dict(self):
        return dict([(attr, getattr(self, attr) for attr in self.data_attributes])

撰写回答