一个类似 dict 的 python 类

我想编写一个行为类似于 dict的自定义类-因此,我从 dict继承。

但是,我的问题是: 是否需要在 __init__()方法中创建一个私有 dict成员?.我不明白这有什么意义,因为如果我只是从 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: < 内置函数 id >

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

我如何更正类 myDict,以便我可以编写这样的代码?

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

[编辑]

我已经编辑了上面的代码示例,以消除在离开办公桌之前出现的愚蠢错误。这是一个输入错误(我应该从错误消息中发现它)。

214529 次浏览

检查 模拟容器类型上的文档。在您的例子中,add的第一个参数应该是 self

这段代码的问题在于:

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


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




md = myDict()
md.add('id', 123)

... 是你的“ add”方法(... 以及任何你想成为类成员的方法)需要有一个明确的“ self”声明为它的第一个参数,比如:

def add(self, 'id', 23):

要实现按键访问项目的运算符重载,请在 医生中查找魔法方法 __getitem____setitem__

请注意,因为 Python 使用 Duck 键入,实际上可能没有理由从语言的 dict 类派生自定义 dict 类——在不知道更多关于您正在尝试做什么的情况下(例如,如果您需要将这个类的一个实例传递到某个除非 isinstance(MyDict(), dict) == True否则会中断的代码中) ,您可能只需要实现 API,使您的类充分地与 dict 类似,并在那里停止就可以了。

像这样

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

现在您可以使用内置函数,比如 dict.get()作为 self.get()

您不需要包装一个隐藏的 self._dict。您的类已经 一个结论。

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}

永远不要继承 Python 的内置 dict!例如 update方法不使用 __setitem__,它们为优化做了很多工作。使用 UserDect。

from collections import UserDict


class MyDict(UserDict):
def __delitem__(self, key):
pass
def __setitem__(self, key, value):
pass

这里有一个替代方案:

class AttrDict(dict):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__dict__ = self


a = AttrDict()
a.a = 1
a.b = 2

我真的找不到这个问题的正确答案

class MyClass(dict):
    

def __init__(self, a_property):
self[a_property] = a_property

你真正需要做的就是定义你自己的 __init__-这就是所有的一切。

另一个例子(稍微复杂一点) :

class MyClass(dict):


def __init__(self, planet):
self[planet] = planet
info = self.do_something_that_returns_a_dict()
if info:
for k, v in info.items():
self[k] = v


def do_something_that_returns_a_dict(self):
return {"mercury": "venus", "mars": "jupiter"}

当您想要嵌入某种逻辑时,最后这个示例很方便。

无论如何... 简而言之,class GiveYourClassAName(dict)足以让你的班级表现得像一个教科书。你在 self上做的任何 dict 操作都会像一个普通的 dict 一样。

这是我最好的解决办法,我用过很多次了。

class DictLikeClass:
...
def __getitem__(self, key):
return getattr(self, key)


def __setitem__(self, key, value):
setattr(self, key, value)
...

你可以这样使用:

>>> d = DictLikeClass()
>>> d["key"] = "value"
>>> print(d["key"])

一个类似于 dict的 python 类

这有什么问题吗?

有人能指出为什么大多数继承代码片段看起来像下面这个吗?

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

大概有一个很好的理由继承 dict (也许你已经传递了一个,你想要一个更具体的 dict 类型) 还有,你有一个很好的理由实例化另一个 dict 来委托(因为这将实例化每个类的实例的 dicts)但这听起来不正确吗?

我自己从来没有碰到过这个用例。我确实喜欢在使用可输入字词的地方输入字词的想法。但是在这种情况下,我更喜欢类型化类属性的想法——而且一个 dict 的全部要点是,您可以给它 任何散列的类型的键和 任何类型的值。

那么为什么我们会看到这样的片段呢?我个人认为,这是一个很容易犯的错误,没有得到纠正,因此随着时间的推移永久化。

我更愿意在这些代码片段中看到这一点,以证明通过继承实现代码重用:

class AlternativeOne(dict):
__slots__ = ()
def __init__(self):
super().__init__()
# other init code here
# new methods implemented here

或者,为了证明重新执行口令的行为,这样做:

from collections.abc import MutableMapping


class AlternativeTwo(MutableMapping):
__slots__ = '_mydict'
def __init__(self):
self._mydict = {}
# other init code here
# dict methods reimplemented and new methods implemented here

通过请求将插槽添加到 dict 子类。

为什么要添加插槽? 内置的 dict实例没有任意的属性:

>>> d = dict()
>>> d.foo = 'bar'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'foo'

如果我们创建一个子类,就像这个问题的答案一样,我们看到我们不会得到相同的行为,因为我们会有一个 __dict__属性,导致我们的字典可能会占用两倍的空间:

my_dict(dict):
"""my subclass of dict"""


md = my_dict()
md.foo = 'bar'

由于上面的代码没有创建错误,所以上面的类实际上并不起作用,“就像 dict一样”

我们可以通过给它空的插槽让它表现得像 dict:

class my_dict(dict):
__slots__ = ()


md = my_dict()

因此,现在尝试使用任意属性将会失败:

>>> md.foo = 'bar'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'my_dict' object has no attribute 'foo'

这个 Python 类的行为更像是 dict

有关如何以及为什么使用插槽的更多信息,请参见此问答: _ _ 槽的用法?

Python 标准库中的 UserDect 就是为此而设计的。