Python OrderedDict __setitem__ 重载
Python OrderedDict __setitem__ overloading
我正在构建一个继承 OrderedDict 的 class,其中每个键 returns 一个列表。我正在寻找重载 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'
如何重载这个?除了可以猴子修补一个添加函数之外,它甚至是 Pythonic/readable 意味着改变 class 行为,或者这是可以接受的,因为继承的函数 (OrderedDict) 没有被触及吗?
您已经可以在 现有的 键上使用 +=
:
>>> from collections import OrderedDict
>>> thedict = OrderedDict()
>>> thedict['a'] = [] # set initial list
>>> thedict['a'] += ['foo']
>>> thedict['a'] += ['bar']
>>> thedict
OrderedDict([('a', ['foo', 'bar'])])
请注意,列表中的 +=
与 list.extend()
基本相同,因此您需要附加列表。
如果您希望它适用于尚不存在的键,请实施 __missing__
method,而不是 __setitem__
:
class ListDict(OrderedDict):
def __missing__(self, key):
self[key] = []
return self[key]
当在 dict[key]
查找过程中缺少一个键时,将调用 __missing__
并且它的 return 值被 returned 而不是引发 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
然后在 __missing__
中使用该类型(并转换直接在 __setitem__
中设置的任何新列表):
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)
之后你可以放弃括号:
>>> thedict = ListDict()
>>> thedict['a'] += 'foo'
>>> thedict['b'] = thedict['b'] + 'bar'
>>> thedict
ListDict([('a', ['foo']), ('b', ['bar'])])
我扩展了 Martijn's ListDict
so you can provide default_factory
and have a similar to collections.defaultdict
的功能 + 按键顺序:
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']
我正在构建一个继承 OrderedDict 的 class,其中每个键 returns 一个列表。我正在寻找重载 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'
如何重载这个?除了可以猴子修补一个添加函数之外,它甚至是 Pythonic/readable 意味着改变 class 行为,或者这是可以接受的,因为继承的函数 (OrderedDict) 没有被触及吗?
您已经可以在 现有的 键上使用 +=
:
>>> from collections import OrderedDict
>>> thedict = OrderedDict()
>>> thedict['a'] = [] # set initial list
>>> thedict['a'] += ['foo']
>>> thedict['a'] += ['bar']
>>> thedict
OrderedDict([('a', ['foo', 'bar'])])
请注意,列表中的 +=
与 list.extend()
基本相同,因此您需要附加列表。
如果您希望它适用于尚不存在的键,请实施 __missing__
method,而不是 __setitem__
:
class ListDict(OrderedDict):
def __missing__(self, key):
self[key] = []
return self[key]
当在 dict[key]
查找过程中缺少一个键时,将调用 __missing__
并且它的 return 值被 returned 而不是引发 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
然后在 __missing__
中使用该类型(并转换直接在 __setitem__
中设置的任何新列表):
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)
之后你可以放弃括号:
>>> thedict = ListDict()
>>> thedict['a'] += 'foo'
>>> thedict['b'] = thedict['b'] + 'bar'
>>> thedict
ListDict([('a', ['foo']), ('b', ['bar'])])
我扩展了 Martijn's ListDict
so you can provide default_factory
and have a similar to collections.defaultdict
的功能 + 按键顺序:
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']