基于BTree的持久化类似字典的对象(常规字典和有序字典),可以用作基类。这是一个相对较重的解决方案,因为每个zc.dict.Dict(以及zc.dict.OrderedDict)至少包含3个持久化对象。如果您打算创建大量此类对象,请记住这一点。要构建,请在此目录中运行`python bootstrap/bootstrap.py`,然后运行`bin/buildout`。强烈推荐使用干净的非系统Python。
项目描述
高效、持久并可继承的字典
如果PersistentDict包含的值超过几个,则效率非常低,而且不建议从BTrees继承。
这个类是对BTree的一个简单包装。它保留了BTree的效率,并且作为基类使用是安全的。此外,它实现了完整的Python字典接口。
>>> from zc.dict import Dict >>> d = Dict() >>> d <zc.dict.dict.Dict object at ...>>>> d['foo'] = 'bar' >>> len(d) 1>>> d['bar'] = 'baz' >>> len(d) 2
注意,Python字典与这个Dict之间的重要区别在于,Python字典使用哈希,而这个使用BTree比较。实际上,这意味着你的键应该是同质的类型。我们在这些示例中使用字符串。
长度是独立维护的,因为在BTree上len操作效率低下,因为它必须唤醒数据库中的所有桶。
>>> d._len <BTrees.Length.Length object at ...> >>> d._len() 2
为了保持小更改的更新效率,我们将它们展开为一系列的setitems。
>>> d.update({'bar': 'moo', 'ding': 'dong', 'beep': 'beep'}) >>> len(d) 4
Dict支持完整的update接口。
>>> d.update([['sha', 'zam'], ['ka', 'pow']]) >>> len(d) 6 >>> d['ka'] 'pow' >>> d.update(left='hook', right='jab') >>> len(d) 8 >>> d['left'] 'hook'
pop需要更新长度。
>>> d.pop('sha') 'zam' >>> d.pop('ka') 'pow' >>> d.pop('left') 'hook' >>> d.pop('right') 'jab' >>> len(d) 4
……除非它不需要。
>>> d.pop('nonexistent') Traceback (most recent call last): ... KeyError: 'nonexistent' >>> d.pop('nonexistent', 42) 42 >>> len(d) 4
setdefault有时也需要更新长度。
>>> len(d) 4 >>> d.setdefault('newly created', 'value') 'value' >>> d['newly created'] 'value' >>> len(d) 5>>> d.setdefault('newly created', 'other') 'value' >>> d['newly created'] 'value' >>> len(d) 5>>> del d['newly created'] # set things back to the way they were...
keys、values和items返回正常的Python列表。由于底层的BTree,这些总是按照键的排序顺序。
>>> d.keys() ['bar', 'beep', 'ding', 'foo']>>> d.values() ['moo', 'beep', 'dong', 'bar']>>> d.items() [('bar', 'moo'), ('beep', 'beep'), ('ding', 'dong'), ('foo', 'bar')]
然而,通过iter方法可以提供有效的BTree迭代器。
>>> iter(d) <OO-iterator object at ...> >>> d.iterkeys() <OO-iterator object at ...>>>> d.iteritems() <OO-iterator object at ...>>>> d.itervalues() <OO-iterator object at ...>
popitem从字典中删除并返回一个键值对
>>> len(d) 4>>> d.popitem() ('bar', 'moo')>>> len(d) 3
copy方法创建一个Dict的副本
>>> c = d.copy() >>> c.items() == d.items() True
然而,由于胆怯,我们不支持比较,除了身份。
>>> c == d False >>> Dict() == {} False >>> d == d True
clear从字典中删除所有键
>>> d.clear() >>> d.keys() [] >>> len(d) 0
其余的字典方法委托给底层的BTree
>>> c.has_key('beep') True >>> 'BEEP' in c False >>> c.get('nonexistent', 'default') 'default'
子类化
为了便于子类化,字典有意具有三个重要特性
所有添加都是通过__setitem__完成的,因此覆盖它将控制添加。
所有删除都是通过pop或clear完成的,因此覆盖这些方法将控制删除。
如果没有传递参数调用__init__,则不会尝试访问update方法。
让我们用一个简单的子类来演示这些。
>>> class Demo(Dict): ... def __setitem__(self, key, value): ... print '__setitem__', key, value ... super(Demo, self).__setitem__(key, value) ... def pop(self, key, *args): ... print 'pop', key, args and arg[0] or '---' ... return super(Demo, self).pop(key, *args) ... def update(self, *args, **kwargs): ... print 'update' ... super(Demo, self).update(*args, **kwargs) ... def clear(self): ... print 'clear' ... super(Demo, self).clear() ...>>> demo1 = Demo() >>> demo2 = Demo([['foo', 'bar'], ['bing', 'baz']], sha='zam') update __setitem__ foo bar __setitem__ bing baz __setitem__ sha zam >>> demo2.setdefault('babble') __setitem__ babble None >>> del demo2['bing'] pop bing --- >>> demo2.popitem() pop babble --- ('babble', None) >>> demo2.clear() clear
回归测试
当设置一个已经存在于字典中的项目时,长度不会增加
>>> d.clear() >>> d['foo'] = 'bar' >>> d['foo'] = 'baz' >>> len(d) 1
有序字典:一个保持顺序的持久容器
有序字典提供了大多数Dict的功能,还提供了记住项目添加顺序的功能。它还提供了重新排序项目的API。
重要的是,有序字典当前使用持久列表来存储顺序,这对于大型集合来说表现不佳,因为每次键或顺序发生变化时,整个键集合都必须被序列化。BList将是首选的数据结构,但它尚未发布。
>>> from zc.dict import OrderedDict >>> d = OrderedDict() >>> d <zc.dict.dict.OrderedDict object at ...>>>> d['foo'] = 'bar' >>> len(d) 1>>> d['bar'] = 'baz' >>> len(d) 2>>> d['foo'] 'bar' >>> d['bar'] 'baz'
键当前是按照添加的顺序排列的。
>>> list(d) ['foo', 'bar']
注意,Python字典与有序字典之间的一个重要区别是,Python字典使用哈希,而这个使用BTree比较。实际上,这意味着你的键应该是同质的类型。我们在这些示例中使用字符串。
长度是独立维护的,因为在BTree上len操作效率低下,因为它必须唤醒数据库中的所有桶。
>>> d._len <BTrees.Length.Length object at ...> >>> d._len() 2
为了保持小更改的更新效率,我们将它们展开为一系列的setitems。
>>> d.update({'bar': 'moo', 'ding': 'dong', 'beep': 'beep'}) >>> len(d) 4
注意,在无序的数据结构中对多个新项目进行更新时,结果将按照未定义的顺序将新项目添加到有序字典的末尾。为了设置我们的顺序,我们需要引入一个新的方法:updateOrder。这个方法是一种强制改变顺序的方法:提供一个新的顺序。
>>> list(d) == ['bar', 'beep', 'ding', 'foo'] False >>> d.updateOrder(('bar', 'beep', 'ding', 'foo')) >>> d.keys() ['bar', 'beep', 'ding', 'foo']
updateOrder期望的是新顺序中整个键列表
>>> d.updateOrder(['bar', 'beep', 'ding']) Traceback (most recent call last): ... ValueError: Incompatible key set.>>> d.updateOrder(['bar', 'beep', 'ding', 'sha', 'foo']) Traceback (most recent call last): ... ValueError: Incompatible key set.>>> d.updateOrder(['bar', 'beep', 'ding', 'sha']) Traceback (most recent call last): ... ValueError: Incompatible key set.>>> d.updateOrder(['bar', 'beep', 'ding', 'ding']) Traceback (most recent call last): ... ValueError: Duplicate keys in order.
Dict支持完整的update接口。如果输入值是有序的,则结果也将是有序的。
>>> d.update([['sha', 'zam'], ['ka', 'pow']]) >>> len(d) 6 >>> d['ka'] 'pow' >>> d.keys() ['bar', 'beep', 'ding', 'foo', 'sha', 'ka']
如果使用关键字参数,则不隐含新项的顺序,但否则它将按预期工作。
>>> d.update(left='hook', right='jab') >>> len(d) 8 >>> d['left'] 'hook'
pop 需要更新长度并保持顺序。
>>> d.pop('sha') 'zam' >>> d.pop('ka') 'pow' >>> d.pop('left') 'hook' >>> d.pop('right') 'jab' >>> len(d) 4 >>> d.keys() ['bar', 'beep', 'ding', 'foo']
……除非它不需要。
>>> d.pop('nonexistent') Traceback (most recent call last): ... KeyError: 'nonexistent' >>> d.pop('nonexistent', 42) 42 >>> len(d) 4
setdefault有时也需要更新长度。
>>> len(d) 4 >>> d.setdefault('newly created', 'value') 'value' >>> d['newly created'] 'value' >>> len(d) 5 >>> d.keys() ['bar', 'beep', 'ding', 'foo', 'newly created']>>> d.setdefault('newly created', 'other') 'value' >>> d['newly created'] 'value' >>> len(d) 5>>> del d['newly created'] # set things back to the way they were...
keys、values和items返回正常的Python列表。由于底层的BTree,这些总是按照键的排序顺序。
>>> d.keys() ['bar', 'beep', 'ding', 'foo']>>> d.values() ['moo', 'beep', 'dong', 'bar']>>> d.items() [('bar', 'moo'), ('beep', 'beep'), ('ding', 'dong'), ('foo', 'bar')]
然而,通过 iter 方法可以提供高效的迭代器。
>>> iter(d) <iterator object at ...> >>> d.iterkeys() <iterator object at ...>>>> d.iteritems() <generator object at ...>>>> d.itervalues() <generator object at ...>
popitem 从字典中删除一个项并返回键值对。
>>> len(d) 4>>> d.popitem() ('bar', 'moo')>>> len(d) 3
copy方法创建一个Dict的副本
>>> c = d.copy() >>> c.items() == d.items() True
然而,由于胆怯,我们不支持比较,除了身份。
>>> c == d False >>> OrderedDict() == {} False >>> d == d True
clear从字典中删除所有键
>>> d.clear() >>> d.keys() [] >>> len(d) 0
其余的字典方法委托给底层的BTree
>>> c.has_key('beep') True >>> 'BEEP' in c False >>> c.get('nonexistent', 'default') 'default'
子类化
为了便于子类化,有序字典具有以下三个重要特性
所有添加都是通过__setitem__完成的,因此覆盖它将控制添加。
所有删除都是通过pop或clear完成的,因此覆盖这些方法将控制删除。
如果没有传递参数调用__init__,则不会尝试访问update方法。
让我们用一个简单的子类来演示这些。
>>> class Demo(OrderedDict): ... def __setitem__(self, key, value): ... print '__setitem__', key, value ... super(Demo, self).__setitem__(key, value) ... def pop(self, key, *args): ... print 'pop', key, args and arg[0] or '---' ... return super(Demo, self).pop(key, *args) ... def update(self, *args, **kwargs): ... print 'update' ... super(Demo, self).update(*args, **kwargs) ... def clear(self): ... print 'clear' ... super(Demo, self).clear() ...>>> demo1 = Demo() >>> demo2 = Demo([['foo', 'bar'], ['bing', 'baz']], sha='zam') update __setitem__ foo bar __setitem__ bing baz __setitem__ sha zam >>> demo2.setdefault('babble') __setitem__ babble None >>> del demo2['bing'] pop bing --- >>> demo2.popitem() pop babble --- ('babble', None) >>> demo2.clear() clear
回归测试
当设置一个已经存在于字典中的项目时,长度不会增加
>>> d.clear() >>> d['foo'] = 'bar' >>> d['foo'] = 'baz' >>> len(d) 1
旧版测试
旧数据库可能需要从 zc.dict.ordered 中找到可导入的内容。
>>> from zc.dict.ordered import OrderedDict as Olde >>> Olde is OrderedDict True
项目详情
zc.dict-1.2.1.tar.gz 的散列
算法 | 散列摘要 | |
---|---|---|
SHA256 | 63ee101c87837551ff4046bf4538cd02609ea033bfff1513f42c67da1f552e79 |
|
MD5 | 4adbf89069c502b3ec1ae9a2b8c96615 |
|
BLAKE2b-256 | a113b52dad4761048331e8a4198af50774c6cafde69d98aa965e1c2115e72791 |