用于dict-able类的Python习语?

时间:2012-06-24 22:15:29

标签: python abc

我想做这样的事情:

class Dictable:
    def dict(self):
        raise NotImplementedError

class Foo(Dictable):
    def dict(self):
        return {'bar1': self.bar1, 'bar2': self.bar2}

有更多的pythonic方法吗?例如,是否可以重置内置转换dict(...)?请注意,我不一定要返回Foo的所有成员变量,我宁愿让每个类决定返回什么。

感谢。

4 个答案:

答案 0 :(得分:5)

Pythonic方式取决于你想做什么。如果您的对象本身不应被视为映射,那么dict方法就完全可以了,但您不应该“重载”dict来处理dictables。您是否需要基类取决于您是否要isinstance(x, Dictable);请注意,hasattr(x, "dict")的用途几乎相同。

如果类 在概念上映射了值的键,那么实现Mapping协议似乎是合适的。即,你实施

  • __getitem__
  • __iter__
  • __len__

并从collections.Mapping继承以获取其他方法。然后你免费获得dict(Foo())。例如:

class Foo(Mapping):
    def __getitem__(self, key):
        if key not in ("bar1", "bar2"):
            raise KeyError("{} not found".format(repr(key))
        return getattr(self, key)

    def __iter__(self):
        yield "bar1"
        yield "bar2"

    def __len__(self):
        return 2

答案 1 :(得分:1)

首先,看看collections.ABC,它描述了Python抽象基类协议(相当于静态语言中的接口)。

然后,决定是否要编写自己的ABC或使用现有的ABC;在这种情况下,Mapping可能就是您想要的。

请注意,虽然dict构造函数(即dict(my_object))不可重写,但如果遇到产生一系列键值对的可迭代对象,它将构造一个dict;即(Python 2;用于Python 3用items替换iteritems):

def __iter__(self):
    return {'bar1': self.bar1, 'bar2': self.bar2}.iteritems()

但是,如果您的类的行为类似于dict,则不应该执行此操作,因为它与Mapping实例的预期行为不同,后者将遍历键,而不是键 - 值对。特别是它会导致for .. in行为不正确。

答案 2 :(得分:0)

你当然可以重载dict(),但你几乎不想!标准库的太多方面取决于可用的字典,您将破坏其大部分功能。你可能会做这样的事情:

class Dictable:
   def dict(self):
     return self.__dict__

答案 3 :(得分:0)

这里的大多数答案都是关于让你的课堂表现得像个字典,这实际上并不是你所要求的。如果你想表达这个想法,“我是一个可以变成字典的类,”我只需要定义一堆类,并让它们各自实现.dict()。 Python倾向于对对象的内容进行duck-typing(对象可以做什么)。 ABC不会增加太多。文档也有同样的目的。