23

在查看Think Complexity中的一些代码时,我注意到他们的Graph类为自己赋值。我从该类中复制了一些重要的行并编写了一个示例类,该类ObjectChild在这种行为上失败了。

class Graph(dict):
    def __init__(self, vs=[], es=[]):
        for v in vs:
            self.add_vertex(v)

        for e in es:
            self.add_edge(e)

    def add_edge(self, e):
        v, w = e
        self[v][w] = e
        self[w][v] = e

    def add_vertex(self, v):
        self[v] = {}

class ObjectChild(object):
    def __init__(self, name):
        self['name'] = name

我确信不同的内置类型都有自己的使用方式,但我不确定这是否应该尝试构建到我的类中。有可能吗,怎么做?这是我不应该打扰的事情,而是依靠简单的构图,例如self.l = [1, 2, 3]?是否应该在内置类型之外避免它?

我问是因为有人告诉我“你几乎不应该从内置的 python 集合继承”;我不愿限制自己的建议。

澄清一下,我知道这ObjectChild不会“工作”,我可以很容易地让它“工作”,但我对这些内置类型的内部工作原理感到好奇,这使得它们的界面不同于object.

4

8 回答 8

13

他们通过继承来完成这个魔法dict。更好的方法是从UserDict或更新的collections.MutableMapping继承

您可以通过执行相同的操作来完成类似的结果:

import collections

class ObjectChild(collections.MutableMapping):
    def __init__(self, name):
        self['name'] = name

您还可以定义两个特殊函数来使您的类类似于字典:__getitem__(self, key)__setitem__(self, key, value). 你可以在Dive Into Python - Special Class Methods中看到一个例子。

于 2012-12-06T04:07:03.100 回答
12

在 Python 3 及更高版本中,只需将这些简单的函数添加到您的类中:

class some_class(object):
    def __setitem__(self, key, value):
        setattr(self, key, value)

    def __getitem__(self, key):
        return getattr(self, key)
于 2020-07-02T12:35:13.113 回答
6

免责声明:我可能是错的。

符号:

self[something]

在 Graph 类中是合法的,因为它继承自 dict。此表示法来自字典 ssyntax,而不是来自类属性声明语法。

尽管与一个类关联的所有命名空间都是字典,但在您的 ChildObject 类中,self 不是字典。因此,您不能使用该语法。

Otoh,在你的类 Graph 中,self 是一个字典,因为它是一个图,并且所有图都是字典,因为它们继承自 dict。

于 2012-12-06T04:10:13.370 回答
6

使用这样的东西好吗?

def mk_opts_dict(d):
    ''' mk_options_dict(dict) -> an instance of OptionsDict '''
    class OptionsDict(object):
        def __init__(self, d):
            self.__dict__ = d

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

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

    return OptionsDict(d)
于 2014-06-22T05:16:24.193 回答
3

我意识到这是一篇旧帖子,但我一直在寻找有关项目分配的一些细节,并在这里偶然发现了答案。泰德的帖子并没有完全错误。为了避免从 dict 继承,你可以让一个类从MutableMapping继承,然后为__setitem__and提供方法__getitem__

此外,该类将需要支持__delitem____iter____len__和(可选)其他继承的 mixin 方法的方法,例如pop. 该文档包含有关详细信息的更多信息。

from collections.abc import MutableMapping
class ItemAssign(MutableMapping):
    def __init__(self, a, b):
        self.a = a
        self.b = b
    def __setitem__(self, k, v):
        setattr(self, k, v)
    def __getitem__(self, k):
        getattr(self, k)
    def __len__(self):
        return 2
    def __delitem__(self, k):
        self[k] = None
    def __iter__(self):
        yield self.a
        yield self.b

示例使用:

>>> x = ItemAssign("banana","apple")
>>> x["a"] = "orange"
>>> x.a
'orange'
>>> del x["a"]
>>> print(x.a)
None
>>> x.pop("b")
'apple'
>>> print(x.b)
None

希望这有助于澄清如何为其他偶然发现这篇文章的人正确实施项目分配:)

于 2018-12-21T06:12:15.273 回答
0

您的 ObjectChild 不起作用,因为它不是 dict 的子类。这些中的任何一个都可以工作:

class ObjectChild(dict):
    def __init__(self, name):
        self['name'] = name

或者

class ObjectChild(object):
    def __init__(self, name):
        self.name = name
于 2012-12-06T04:07:59.520 回答
0

您不需要从 dict 继承。如果您提供setitemgetitem方法,您也会得到我相信的所需行为。

class a(object):
    def __setitem__(self, k, v):
        self._data[k] = v
    def __getitem__(self, k):
        return self._data[k]
    _data = {}
于 2015-02-03T15:39:51.570 回答
0

关于 <dict> 继承的小备忘录

对于那些想要继承dict的人。在这种情况下, MyDict 将在其中包含原始 dict 的浅表副本。

class MyDict(dict):
    ...

d = {'a': 1}
md = MyDict(d)

print(d['a'])   # 1
print(md['a'])  # 1

md['a'] = 'new'

print(d['a'])   # 1
print(md['a'])  # new

当你有一棵嵌套的字典树并且你想将它的一部分转换为一个对象时,这可能会导致问题。更改此对象不会影响其父对象

root = {
    'obj': {
        'a': 1,
        'd': {'x': True}
    }
}
obj = MyDict(root['obj'])

obj['a'] = 2
print(root)   # {'obj': {'a': 1, 'd': {'x': True}}} # 'a' is the same

obj['d']['x'] = False
print(root)   # {'obj': {'a': 1, 'd': {'x': True}}} # 'x' chanded
于 2020-06-12T09:12:22.727 回答