一个像字典的Python类

168 投票
11 回答
250962 浏览
提问于 2025-04-16 06:03

我想写一个自定义的类,让它的行为像 dict(字典)一样,所以我打算从 dict 继承。

不过,我有个问题:我在 __init__() 方法里需要创建一个私有的 dict 成员吗?我觉得没必要,因为我直接继承 dict 就已经有字典的功能了。

有没有人能告诉我,为什么大多数继承的示例看起来像下面这个?

class CustomDictOne(dict):
   def __init__(self):
      self._mydict = {} 

   # other methods follow

而不是更简单的...

class CustomDictTwo(dict):
   def __init__(self):
      # initialize my other stuff here ...

   # other methods follow

其实,我觉得这个问题的答案可能是为了让用户不能直接访问你的字典(也就是说,他们必须使用你提供的访问方法)。

但是,关于数组访问操作符 [] 呢?那该怎么实现呢?到目前为止,我还没看到过一个示例展示如何重写 [] 操作符。

所以,如果在自定义类中没有提供 [] 访问函数,继承的基类方法会在一个不同的字典上操作吗?

我尝试了下面的代码片段来测试我对 Python 继承的理解:

class myDict(dict):
    def __init__(self):
        self._dict = {}

    def add(self, id, val):
        self._dict[id] = val


md = myDict()
md.add('id', 123)
print md[id]

结果我遇到了以下错误:

KeyError: < built-in function id>

上面的代码有什么问题吗?

我该如何修正 myDict 类,以便我可以写出这样的代码?

md = myDict()
md['id'] = 123

[编辑]

我已经编辑了上面的代码示例,修正了我之前匆忙离开桌子时犯的愚蠢错误。那是个拼写错误(我应该从错误信息中发现它)。

11 个回答

122

像这样

class CustomDictOne(dict):
   def __init__(self, *arg, **kw):
      super(CustomDictOne, self).__init__(*arg, **kw)

现在你可以使用内置的函数,比如 dict.get(),就像用 self.get() 一样。

你不需要再包裹一个隐藏的 self._dict。你的类已经就是一个字典了。

147
class Mapping(dict):

    def __setitem__(self, key, item):
        self.__dict__[key] = item

    def __getitem__(self, key):
        return self.__dict__[key]

    def __repr__(self):
        return repr(self.__dict__)

    def __len__(self):
        return len(self.__dict__)

    def __delitem__(self, key):
        del self.__dict__[key]

    def clear(self):
        return self.__dict__.clear()

    def copy(self):
        return self.__dict__.copy()

    def has_key(self, k):
        return k in self.__dict__

    def update(self, *args, **kwargs):
        return self.__dict__.update(*args, **kwargs)

    def keys(self):
        return self.__dict__.keys()

    def values(self):
        return self.__dict__.values()

    def items(self):
        return self.__dict__.items()

    def pop(self, *args):
        return self.__dict__.pop(*args)

    def __cmp__(self, dict_):
        return self.__cmp__(self.__dict__, dict_)

    def __contains__(self, item):
        return item in self.__dict__

    def __iter__(self):
        return iter(self.__dict__)

    def __unicode__(self):
        return unicode(repr(self.__dict__))


o = Mapping()
o.foo = "bar"
o['lumberjack'] = 'foo'
o.update({'a': 'b'}, c=44)
print 'lumberjack' in o
print o

In [187]: run mapping.py
True
{'a': 'b', 'lumberjack': 'foo', 'foo': 'bar', 'c': 44}

当然可以!请把你想要翻译的内容发给我,我会帮你用简单易懂的语言解释清楚。

48

查看一下关于模拟容器类型的文档。在你的情况下,add函数的第一个参数应该是self

撰写回答