Package: dictionaries
ContentsQuick overviewInstallationUsageQuick-starterAttribute-style item access“Classic” attribute-style dict item access (as people know it)Attribute-style item access through theitemsattribute of the dictionaryDictionary classesFrozenDictandFrozenOrderedDictReadonlyDictProxyExtendedcopymethodQuick overviewAttribute-style item access is provided by all dictionary classes of this library.5 dictionary implementations:Standard dictionaries with attribute-style item access and a smartercopy()method with update parameters:DictOrderedDictImmutable/hashable versions of the previous two dictionaries:FrozenDictFrozenOrderedDictA wrapper that can be used to create a readonly view of another dictionary instance:ReadonlyDictProxyInstallationpipinstalldictionariesAlternatively you can download the distribution from the following places:https://pypi.python.org/pypi/dictionaries#downloadshttps://github.com/pasztorpisti/py-dictionaries/releasesUsageQuick-starterAfter installing the library you can import the dictionary classes the following way:fromdictionariesimportDict,OrderedDict,FrozenDict,FrozenOrderedDict,ReadonlyDictProxyTheir interface is as standard as possible so I assume you know how to deal with them.Attribute-style item accessThe attribute-style dictionary item access can be really convenient in many cases but it has issues. The most
obvious issue is that the attributes of the dictionary are in conflict with your item keys.
For this reason attribute-style access is a little bit “stinky” (especially when you try to implement it) and
to aid this problem I’ve recently come up with a different kind of attribute-style access implementation. This
library provides both the usual way (discussed here and there) and also my method. (Yes, I know that providing 2 or
more ways isn’t pythonic but you have to experiment to find out what works and what doesn’t…) Later I might
drop one of them.“Classic” attribute-style dict item access (as people know it)As mentioned previously the attributes of the dictionary instance (likecopy) conflict with the keys of
your items. In order to be able to access dictionary methods we have to provide priority for the dictionary
attributes over the item keys.>>>fromdictionariesimportDict>>>d=Dict(copy=True,name='example')>>>d.my_item=5# this is equivalent to d['my_item'] = 5>>>d{'my_item':5,'name':'example','copy':True}>>>d.my_item5>>>d.name'example'>>>d.copy# the 'copy' item conflicts with the copy method!!!<boundmethodExtendedCopyMixin.copyof{'my_item':5,'name':'example','copy':True}>Attribute-style item access through theitemsattribute of the dictionaryMy recent invention aids the previous conflict between dictionary attributes and item keys. By typing
a little bit more you can use attribute-style access without worrying about conflicts:>>>fromdictionariesimportDict>>>d=Dict(copy=True,name='example')>>>d.items.my_item=5>>>d{'my_item':5,'name':'example','copy':True}>>>d.items.my_item5>>>d.items.name'example'>>>d.items.copyTrue>>>d.items()# using items() the good old way still worksdict_items([('my_item',5),('name','example'),('copy',True)])You can use theitems“method” of your dictionary the old way by calling it but you can also use it as an
object that provides attribute style access to your items. There are no conflicts because the only attributes
ofitemsare the keys of your dictionary items.Besides attribute-style item access theitemsattribute provides a limited set of the typical dictionary interface:__contains__,__iter__,__len__Item assignment/retrieval/deletion with both attribute-style access and subscript notation.This can be useful if you have to pass around theitemsobject to be accessed elsewhere.>>>fromdictionariesimportDict>>>d=Dict(copy=True,name='example',my_item=5)>>>'name'indTrue>>>iter(d.items)<dict_keyiteratorobjectat0x104254e08>>>>list(d.items)['my_item','name','copy']>>>len(d.items)3>>>deld.items['name']>>>deld.items.copy# no conflict with Dict.copy :-)>>>d{'my_item':5}Dictionary classesFrozenDictandFrozenOrderedDictThese are “frozen”/immutable like thefrozensetprovided by the standard library. After creation
their value doesn’t change during their lifetime. Like other immutable objects, instances of
these dictionaries are hashable given that all objects inside them are also hashable.>>>fromdictionariesimportFrozenDict>>>d=FrozenDict(item1=1,item2=2)>>>d['item3']=3# we shouldn't be able to modify an immutable objectTraceback(mostrecentcalllast):File"<stdin>",line1,in<module>TypeError:'FrozenDict'objectdoesnotsupportitemassignment>>>deld['item2']# we shouldn't be able to modify an immutable objectTraceback(mostrecentcalllast):File"<stdin>",line1,in<module>TypeError:'FrozenDict'objectdoesnotsupportitemdeletion>>>d<FrozenDict{'item1':1,'item2':2}>>>>hash(d)8310388587437647073ReadonlyDictProxySometimes you have to pass around some of your dictionaries but you want to make sure that no one modifies them. In this
case what you should do is creating aReadonlyDictProxywrapper around your dictionary and passing around the
wrapper instead of your original wrapped one. TheReadonlyDictProxyinstance will delegate all requests to your
original dictionary except those requests that involve data modification (like item assignment/deletion,update(),
etc…). Of course if you  modify the wrapped dictionary then the users of the readonly proxy will notice the changes.
The proxy keeps most of the behavior provided by the wrapped dict, for example if the wrapped dict is an ordered one
then the readonly proxy also behaves as ordered.>>>fromdictionariesimportReadonlyDictProxy,OrderedDict>>>wrapped=OrderedDict.fromkeys(['item1','item2','item3'])>>>proxy=ReadonlyDictProxy(wrapped)>>>wrappedOrderedDict([('item1',None),('item2',None),('item3',None)])>>>proxy<ReadonlyDictProxyOrderedDict([('item1',None),('item2',None),('item3',None)])>Changes to the wrapped dict instance are reflected by the readonly proxy:>>>delwrapped['item3']>>>wrapped['new_item']='brand new'>>>wrappedOrderedDict([('item1',None),('item2',None),('new_item','brand new')])>>>proxy<ReadonlyDictProxyOrderedDict([('item1',None),('item2',None),('new_item','brand new')])>Trying to modify the proxy object will fail:>>>proxy['trying hard']='to assign'# the proxy is readonly, assignment failsTraceback(mostrecentcalllast):File"<stdin>",line1,in<module>TypeError:'ReadonlyDictProxy'objectdoesnotsupportitemassignment>>>delproxy['item1']# the proxy is readonly, deletion failsTraceback(mostrecentcalllast):File"<stdin>",line1,in<module>TypeError:'ReadonlyDictProxy'objectdoesnotsupportitemdeletionCopying aReadonlyDictProxyinstance with itscopymethod creates anotherReadonlyDictProxyinstance that wraps the exact same object:>>># Both of these statements create another wrapper/proxy around wrapped:>>>proxy_copy=proxy.copy()>>>proxy_copy2=ReadonlyDictProxy(wrapped)>>>>>># Now we have 3 proxy objects wrapping the same dictionary (wrapped):>>>wrapped.clear()>>>wrapped.items.woof='woof'>>>proxy<ReadonlyDictProxyOrderedDict([('woof','woof')])>>>>proxy_copy<ReadonlyDictProxyOrderedDict([('woof','woof')])>>>>proxy_copy2<ReadonlyDictProxyOrderedDict([('woof','woof')])>ExtendedcopymethodAll dictionary classes exceptReadonlyDictProxyhave acopymethod that receives**kwargs. These
keyword arguments are treated as dictionary items and used to create a copy that is updated with them.>>>fromdictionariesimportDict>>>d=Dict(a=0,b=1)>>>d2=d.copy(b=2,c=3)>>>d{'a':0,'b':1}>>>d2{'a':0,'b':2,'c':3}