Python OrderedDict\uuuuu setitem\uuuuuuuuu重载

Python OrderedDict\uuuuu setitem\uuuuuuuuu重载,python,dictionary,overloading,ordereddictionary,Python,Dictionary,Overloading,Ordereddictionary,我正在构建一个继承OrderedDict的类,其中每个键都返回一个列表。我希望重载setitem,这样,如果键不存在,新赋值会立即将值放入列表,否则新值会追加到列表中。以下似乎正在发挥作用: from collections import OrderedDict class ListDict(OrderedDict): def __init__(self): super(ListDict, self).__init__() def __setitem__(se

我正在构建一个继承OrderedDict的类,其中每个键都返回一个列表。我希望重载setitem,这样,如果键不存在,新赋值会立即将值放入列表,否则新值会追加到列表中。以下似乎正在发挥作用:

from collections import OrderedDict

class ListDict(OrderedDict):
    def __init__(self):
        super(ListDict, self).__init__()

    def __setitem__(self, key, value):
        if key in self:
            self[key].append(value)
        else:
            super(ListDict, self).__setitem__(key, [value])

thedict = ListDict()

thedict['a'] = 'first item'
thedict['b'] = 'another first item'
thedict['a'] = 'a second item?'

print thedict
其中打印:

$ python inheritex.py
ListDict([('a', ['first item', 'a second item?']), ('b', ['another first item'])])
与其附加赋值运算符“=”,我更希望新项附加“+=”,甚至类似于:

ListDict['key'] = ListDict['key'] + 'value'

你怎么能让它超载呢?除了可以对add函数进行猴子补丁之外,它是一种改变类行为的Pythonic/可读方法,还是因为继承的函数(OrderedDict)未被触及而可以接受?

您已经可以对现有键使用
+=

请注意,列表上的
+=
list.extend()
基本相同,因此需要附加列表

如果您希望此操作适用于尚不存在的密钥,请实现,而不是
\uuuuuuu setitem\uuuuuu

class ListDict(OrderedDict):
    def __missing__(self, key):
        self[key] = []
        return self[key]
class ListDict(OrderedDict):
    def __missing__(self, key):
        self[key] = ConcatList()
        return self[key]
    def __setitem__(self, key, value):
        if not isinstance(key, ConcatList):
           value = ConcatList([value])
        super(ListDict, self).__setitem__(key, value)
当在
dict[key]
查找过程中某个键丢失时,将调用
\uuuuuu missing\uuuuu
,并返回其返回值,而不是引发
KeyError

现在
+
+=
也可以处理丢失的键:

>>> thedict = ListDict()
>>> thedict['a'] += ['foo', 'bar']
>>> thedict['b'] = thedict['b'] + ['spam', 'ham']
>>> thedict
ListDict([('a', ['foo', 'bar']), ('b', ['spam', 'ham'])])
如果连接必须在不添加列表的情况下工作,则还可以生成自定义列表子类:

class ConcatList(list):
    def __add__(self, value):
        return type(self)(super(ContactList, self).__add__([value]))
    def __iadd__(self, value):
        self.append(value)
        return self
然后在
\uuuuu missing\uuuuu
中使用该类型(并转换直接在
\uuuuuuu setitem\uuuuu
中设置的任何新列表):

在此之后,您可以放弃支架:

>>> thedict = ListDict()
>>> thedict['a'] += 'foo'
>>> thedict['b'] = thedict['b'] + 'bar'
>>> thedict
ListDict([('a', ['foo']), ('b', ['bar'])])

您已经可以在现有密钥上使用
+=

请注意,列表上的
+=
list.extend()
基本相同,因此需要附加列表

如果您希望此操作适用于尚不存在的密钥,请实现,而不是
\uuuuuuu setitem\uuuuuu

class ListDict(OrderedDict):
    def __missing__(self, key):
        self[key] = []
        return self[key]
class ListDict(OrderedDict):
    def __missing__(self, key):
        self[key] = ConcatList()
        return self[key]
    def __setitem__(self, key, value):
        if not isinstance(key, ConcatList):
           value = ConcatList([value])
        super(ListDict, self).__setitem__(key, value)
当在
dict[key]
查找过程中某个键丢失时,将调用
\uuuuuu missing\uuuuu
,并返回其返回值,而不是引发
KeyError

现在
+
+=
也可以处理丢失的键:

>>> thedict = ListDict()
>>> thedict['a'] += ['foo', 'bar']
>>> thedict['b'] = thedict['b'] + ['spam', 'ham']
>>> thedict
ListDict([('a', ['foo', 'bar']), ('b', ['spam', 'ham'])])
如果连接必须在不添加列表的情况下工作,则还可以生成自定义列表子类:

class ConcatList(list):
    def __add__(self, value):
        return type(self)(super(ContactList, self).__add__([value]))
    def __iadd__(self, value):
        self.append(value)
        return self
然后在
\uuuuu missing\uuuuu
中使用该类型(并转换直接在
\uuuuuuu setitem\uuuuu
中设置的任何新列表):

在此之后,您可以放弃支架:

>>> thedict = ListDict()
>>> thedict['a'] += 'foo'
>>> thedict['b'] = thedict['b'] + 'bar'
>>> thedict
ListDict([('a', ['foo']), ('b', ['bar'])])
我扩展了
ListDict
,因此您可以提供
default\u factory
,并具有类似于的功能+键顺序:

class OrderedDefaultDict(OrderedDict):
    def __init__(self, default_factory=None):
        self.default_factory = default_factory

    def __missing__(self, key):
        if self.default_factory is None:
            raise KeyError
        self[key] = self.default_factory()
        return self[key]

list_dict = OrderedDefaultDict(list)
list_dict['first'].append(1)
list_dict['second'].append(2)
list_dict['third'].append(3)
assert list(list_dict.keys()) == ['first', 'second', 'third']
assert list(list_dict.values()) == [[1], [2], [3]]

list_dict.move_to_end('first')
assert list(list_dict.keys()) == ['second', 'third', 'first']
我扩展了
ListDict
,因此您可以提供
default\u factory
,并具有类似于的功能+键顺序:

class OrderedDefaultDict(OrderedDict):
    def __init__(self, default_factory=None):
        self.default_factory = default_factory

    def __missing__(self, key):
        if self.default_factory is None:
            raise KeyError
        self[key] = self.default_factory()
        return self[key]

list_dict = OrderedDefaultDict(list)
list_dict['first'].append(1)
list_dict['second'].append(2)
list_dict['third'].append(3)
assert list(list_dict.keys()) == ['first', 'second', 'third']
assert list(list_dict.values()) == [[1], [2], [3]]

list_dict.move_to_end('first')
assert list(list_dict.keys()) == ['second', 'third', 'first']

我怀疑您也可以使用多重继承将
orderedict
defaultdict
组合(您只需重载
\uuuu init\uuuu
即可将
list
作为工厂函数传递给
defaultdict
类)。@Blckknght:也许,但是,只使用一个自定义的
\uuuuuuuuuuuuuuuu
要比弄清楚如何让
defaultdict
OrderedDict
初始化器满意容易得多。是的,由于某种冲突,它似乎实际上不起作用(至少在Python的最新版本中是这样。当我看到你的文章涵盖了大部分相同的内容时,我正在探索我自己的答案。@Blckknght:两者都没有合作的
\uuuuu init\uuuu
,所以你必须明确地调用它们。@MartijnPieters:
\uu missing\uuuuu
看起来比
\uu setitem\uuuu
优雅得多,尽管我不太喜欢它)从用户输入shell的角度来看,每次有人使用
+=
时都需要列表括号。不过,将其包装到函数中应该很容易。谢谢!我怀疑您也可以使用多重继承将
OrderedDict
defaultdict
(只需重载
\uuuu init\uuuu
即可将
list
作为工厂函数传递给
defaultdict
类)@Blckknght:也许吧,但是仅仅使用一个自定义的
\uuuu缺少的
要比弄清楚如何让
defaultdict
OrderedDict
初始化器满意容易得多。是的,由于某种冲突,它似乎实际上不起作用(至少在Python的最新版本中是这样。当我看到你的文章涵盖了大部分相同的内容时,我正在探索我自己的答案。@Blckknght:两者都没有合作的
\uuuuu init\uuuu
,所以你必须明确地调用它们。@MartijnPieters:
\uu missing\uuuuu
看起来比
\uu setitem\uuuu
优雅得多,尽管我不太喜欢它)从用户输入shell的角度来看,每次有人使用
+=
时都需要列表括号。不过,将其包装到函数中应该很容易。谢谢!FWIW,
如果键入self
要比
如果键入self.keys()好得多。
:-)@mgilson:Ooof你是对的。>.<我仍然看到继承代码中有
self
,感到头晕目眩…FWIW,
如果输入self
输入self.keys()
:-)@mgilson:Ooof你是对的。<我仍然看到继承代码中有
self并且感到头晕目眩。。。