如何使python类支持项目分配?

时间:2012-12-06 03:57:56

标签: python inheritance built-in-types object-composition

在查看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的孩子不同。

8 个答案:

答案 0 :(得分:7)

他们通过继承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找到相关示例。

答案 1 :(得分:5)

免责声明:我可能错了。

符号:

self[something]

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

虽然与类关联的所有命名空间都是字典,但在类ChildObject中,self不是字典。因此,您无法使用该语法。

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

答案 2 :(得分:4)

只需将以下简单函数添加到您的类中即可:

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

    def __getitem__(self, key):
        return getattr(self, key)

答案 3 :(得分:3)

使用这样的东西好吗?

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)

答案 4 :(得分:2)

您的ObjectChild不起作用,因为它不是dict的子类。这些都可以起作用:

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

class ObjectChild(object):
    def __init__(self, name):
        self.name = name

答案 5 :(得分:2)

我意识到这是一篇过时的文章,但是我一直在寻找有关项目分配的一些细节,并偶然发现了这里的答案。 Ted's post并非完全错误。为了避免从dict继承,可以使一个类从MutableMapping继承,然后为__setitem____getitem__提供方法。

此外,该类将需要支持__delitem____iter____len__和(可选)其他继承的混合方法(如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):
        if k == "a":
            self.a = v
        if k == "b":
            self.b = v
    def __getitem__(self, k):
        if k == "a":
            return self.a
        if k == "b":
            return self.b
    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

希望这有助于阐明如何为在此帖子中绊脚的其他人正确实施项目分配:)

答案 6 :(得分:0)

你不需要继承dict。如果您提供 setitem getitem 方法,您也会获得我认为的理想行为。

class a(object):
    def __setitem__(self, k, v):
        self._data[k] = v
    def __getitem__(self, k):
        return self._data[k]
    _data = {}

答案 7 :(得分:0)

关于继承的小备忘录

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

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