一个像dict一样的python类

问题:一个像dict一样的python类

我想编写一个行为类似的自定义类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

[编辑]

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

I want to write a custom class that behaves like dict – so, I am inheriting from dict.

My question, though, is: Do I need to create a private dict member in my __init__() method?. I don’t see the point of this, since I already have the dict behavior if I simply inherit from dict.

Can anyone point out why most of the inheritance snippets look like the one below?

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

   # other methods follow

Instead of the simpler…

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

   # other methods follow

Actually, I think I suspect the answer to the question is so that users cannot directly access your dictionary (i.e. they have to use the access methods that you have provided).

However, what about the array access operator []? How would one implement that? So far, I have not seen an example that shows how to override the [] operator.

So if a [] access function is not provided in the custom class, the inherited base methods will be operating on a different dictionary?

I tried the following snippet to test out my understanding of Python inheritance:

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]

I got the following error:

KeyError: < built-in function id>

What is wrong with the code above?

How do I correct the class myDict so that I can write code like this?

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

[Edit]

I have edited the code sample above to get rid of the silly error I made before I dashed away from my desk. It was a typo (I should have spotted it from the error message).


回答 0

查看有关模拟容器类型的文档。您的情况下,第一个参数add应为self

Check the documentation on emulating container types. In your case, the first parameter to add should be self.


回答 1

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}
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}

回答 2

像这样

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

现在你可以使用内置的功能,如dict.get()作为self.get()

您无需包装隐藏的self._dict。您的类已经字典。

Like this

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

Now you can use the built-in functions, like dict.get() as self.get().

You do not need to wrap a hidden self._dict. Your class already is a dict.


回答 3

为了完整起见,这里是@björn-pollex提到的有关最新Python 2.x(截至撰写本文时为2.7.7)的文档的链接:

模拟容器类型

(很抱歉,您未使用注释功能,但是stackoverflow不允许这样做。)

For the sake of completeness, here is the link to the documentation mentioned by @björn-pollex for the latest Python 2.x (2.7.7 as of the time of writing):

Emulating Container Types

(Sorry for not using the comments function, I’m just not allowed to do so by stackoverflow.)


回答 4

此代码段的问题:

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):

要实现操作符重载以按键访问项目,请在文档中查找magic方法__getitem____setitem__

请注意,由于Python使用Duck Typing,因此实际上可能没有理由从语言的dict类派生自定义dict类-无需更多了解您要执行的操作(例如,如果需要传递此方法的实例)类插入某个可能会中断的代码(除非isinstance(MyDict(), dict) == True),您最好实现一个使类足够像字典的API,然后停在那里。

The problem with this chunk of code:

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

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


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

…is that your ‘add’ method (…and any method you want to be a member of a class) needs to have an explicit ‘self’ declared as its first argument, like:

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

To implement the operator overloading to access items by key, look in the docs for the magic methods __getitem__ and __setitem__.

Note that because Python uses Duck Typing, there may actually be no reason to derive your custom dict class from the language’s dict class — without knowing more about what you’re trying to do (e.g, if you need to pass an instance of this class into some code someplace that will break unless isinstance(MyDict(), dict) == True), you may be better off just implementing the API that makes your class sufficiently dict-like and stopping there.


回答 5

这是一个替代解决方案:

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

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

Here is an alternative solution:

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

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

回答 6

我真的在任何地方都看不到正确的答案

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),足以使您的课堂像字典一样行事。您执行的任何dict操作都self将像常规dict。

I really don’t see the right answer to this anywhere

class MyClass(dict):
    
    def __init__(self, a_property):
        self[a_property] = a_property

All you are really having to do is define your own __init__ – that really is all that there is too it.

Another example (little more complex):

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"}

This last example is handy when you want to embed some kind of logic.

Anyway… in short class GiveYourClassAName(dict) is enough to make your class act like a dict. Any dict operation you do on self will be just like a regular dict.


回答 7

这是我最好的解决方案。我使用了很多次。

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"])

This is my best solution. I used this many times.

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

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

You can use like:

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

回答 8

永远不要继承自Python内置字典!例如update方法woldn’t use __setitem__,他们做了很多优化工作。使用UserDict。

from collections import UserDict

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

Don’t inherit from Python built-in dict, ever! for example update method woldn’t use __setitem__, they do a lot for optimization. Use UserDict.

from collections import UserDict

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