如何将对象转换为自定义字典?

6

我有一个Python类,它存储一些字段并具有一些属性,例如

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

  @property
  def z(self):
    return self.x+1

我需要对这个类做哪些修改才能实现这个功能?

>>> a = A(1,5)
>>> dict(a)
{'y':5, 'z':2}

我在哪里指定我想要返回yz?我不能只使用a.__dict__,因为它将包含x但不包括z。我希望能够指定任何可以通过__getattribute__访问的内容。


你能否不重写a.__dict__呢? - tlunter
1
a.__dict__ 是 Python 类存储字段的一个非常重要的部分,我非常不愿意去修改它。 - murgatroid99
3个回答

13

为你的类添加一个__iter__()方法,它以键值对的形式返回对象项的迭代器。然后可以直接将对象实例传递给dict()构造函数,因为它接受一个键值对序列。

def __iter__(self):
    for key in "y", "z":
        yield key, getattr(self, key)

如果你希望这个功能更加灵活,可以允许属性列表在子类中或程序中轻松覆盖,那么你可以将键列表存储为类的属性:

_dictkeys = "y", "z"

def __iter__(self):
    for key in self._dictkeys:
        yield key, getattr(self, key)
如果你想让字典包含所有属性(包括从父类继承的属性),请尝试以下代码:
def __iter__(self):
    for key in dir(self):
        if not key.startswith("_"):
            value = getattr(self, key)
            if not callable(value):
                yield key, value

这将排除以“_”开头的成员以及可调用对象(例如类和函数)。


太棒了,第二个代码块正是我在寻找的。 - murgatroid99

5
我认为解决这个问题的一个合理方法是创建一个asdict方法。当你说你想指定字典包含哪些键时,我假设你希望该信息在调用方法时被传递。如果不是这个意思,请告诉我。(这包括了kindall的优秀建议。)
class A(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    @property
    def z(self):
        return self.x+1

    def asdict(self, *keys):
        if not keys:
            keys = ['y', 'z']
        return dict((key, getattr(self, key)) for key in keys)

已测试:

>>> A(1, 2).asdict('x', 'y')
{'y': 2, 'x': 1}
>>> A(1, 2).asdict()
{'y': 2, 'z': 2}

我喜欢这个因为它让你可以即时指定键。不过你可能想要有一个默认列表。 - kindall
这与我已经拥有的非常相似,但我的特别兴趣在于使用内置的 dict - murgatroid99
为容器提供默认值的便捷快捷方式:keys = keys or ['y', 'z'] - kindall

0
解决这个问题的一种天真的方法如下。如果您已经错过了,我只是在指出这一点,它可能不足以满足您的需求。
>>> dict(y=a.y, z=a.z)
>>> {'y': 5, 'z': 2}

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