4

我想做这样的事情:

class Dictable:
    def dict(self):
        raise NotImplementedError

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

有没有更蟒蛇的方式来做到这一点?例如,是否可以重载内置转换dict(...)?请注意,我不一定要返回 的所有成员变量Foo,我宁愿让每个类决定返回什么。

谢谢。

4

4 回答 4

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
于 2012-06-24T22:33:35.690 回答
1

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

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

请注意,尽管dict构造函数 (ie dict(my_object)) 是不可覆盖的,但如果它遇到一个产生一系列键值对的可迭代对象,它将从中构造一个 dict;即(Python 2;对于 Python 3 替换itemsiteritems):

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

但是,如果您的类旨在表现得像 adict您不应该这样做,因为它与Mapping实例的预期行为不同,即迭代键,而不是键值对。特别是它会导致for .. in行为不正确。

于 2012-06-24T22:42:54.093 回答
0

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

class Dictable:
   def dict(self):
     return self.__dict__
于 2012-06-24T22:29:58.773 回答
0

这里的大多数答案都是关于让你的班级表现得像一个字典,这实际上不是你问的。如果你想表达这样的想法,“我是一个可以变成字典的类”,我会简单地定义一堆类并让它们每个都实现 .dict()。Python 偏爱鸭子类型(对象可以做什么)而不是对象是什么。ABC并没有增加太多。文档具有相同的目的。

于 2012-06-24T22:54:14.643 回答