我想编写一个行为类似于dict
的自定义类 - 所以,我继承自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:<内置函数ID>
上面的代码出了什么问题?
如何更正类myDict
以便我可以编写这样的代码?
md = myDict()
md['id'] = 123
[编辑]
我已经编辑了上面的代码示例,以摆脱我在离开办公桌之前犯下的愚蠢错误。这是一个错字(我应该从错误信息中发现它)。
答案 0 :(得分:87)
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}
答案 1 :(得分:68)
喜欢这个
class CustomDictOne(dict):
def __init__(self,*arg,**kw):
super(CustomDictOne, self).__init__(*arg, **kw)
现在您可以使用内置函数,例如dict.get()
作为self.get()
。
您无需包装隐藏的self._dict
。您的班级 是一个词典。
答案 2 :(得分:32)
查看emulating container types上的文档。在您的情况下,add
的第一个参数应为self
。
答案 3 :(得分:8)
为了完整起见,这里是@björn-pollex提到的最新Python 2.x文档的链接(截至撰写本文时为2.7.7):
(很抱歉没有使用评论功能,我只是不允许通过stackoverflow这样做。)
答案 4 :(得分:3)
这段代码的问题:
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):
要实现操作员重载以按键访问项目,请在docs中查看魔术方法__getitem__
和__setitem__
。
请注意,因为Python使用Duck Typing,实际上没有理由从语言的dict类派生你的自定义dict类 - 不知道你正在尝试做什么(例如,如果你需要通过将这个类的实例放到某些代码中,除非isinstance(MyDict(), dict) == True
),否则你可能会更好地实现使你的类充分类似dict并停在那里的API。
答案 5 :(得分:1)
我真的在任何地方都看不到正确的答案
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。
答案 6 :(得分:1)
行为类似于dict的python类
为什么要添加插槽?内置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
。”
我们可以给它留空的位置,使其像字典一样:
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
。
有关如何以及为什么使用插槽的更多信息,请参见以下问答:Usage of __slots__?
答案 7 :(得分:1)
UserDict 就是为此目的而设计的。
答案 8 :(得分:0)
永远不要继承自Python内置字典!例如update
方法根本不使用__setitem__
,它们在优化方面做了很多工作。使用UserDict。
from collections import UserDict
class MyDict(UserDict):
def __delitem__(self, key):
pass
def __setitem__(self, key, value):
pass
答案 9 :(得分:0)
这是替代解决方案:
class AttrDict(dict):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__dict__ = self
a = AttrDict()
a.a = 1
a.b = 2
答案 10 :(得分:0)
这是我最好的解决方案。我用了很多次。
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"])