Ordered dictionary.
Project description
odict
=====
Dictionary in which the *insertion* order of items is preserved (using an
internal double linked list). In this implementation replacing an existing
item keeps it at its original position.
Internal representation: values of the dict:
::
[pred_key, val, succ_key]
The sequence of elements uses as a double linked list. The ``links`` are dict
keys. ``self.lh`` and ``self.lt`` are the keys of first and last element
inseted in the odict. In a C reimplementation of this data structure, things
can be simplified (and speed up) a lot if given a value you can at the same
time find its key. With that, you can use normal C pointers.
Memory used (Python 2.5)
------------------------
-set(int): 28.2 bytes/element
-dict(int:None): 36.2 bytes/element
-odict(int:None): 102 bytes/element
Performance
-----------
When running the benchmark script, you get results similar to the one below
on recent common hardware.
Adding and deleting ``dict`` objects.
::
+----------------+--------------------+
| Add 1000 | 0.000653028488159 |
+----------------+--------------------+
| Delete 1000 | 0.000339031219482 |
+----------------+--------------------+
| Add 10000 | 0.00774908065796 |
+----------------+--------------------+
| Delete 10000 | 0.00406503677368 |
+----------------+--------------------+
| Add 100000 | 0.130412101746 |
+----------------+--------------------+
| Delete 100000 | 0.0517508983612 |
+----------------+--------------------+
| Add 1000000 | 3.17614817619 |
+----------------+--------------------+
| Delete 1000000 | 0.564585924149 |
+----------------+--------------------+
Adding and deleting ``odict`` objects.
::
+----------------+--------------------+
| Add 1000 | 0.0096800327301 |
+----------------+--------------------+
| Delete 1000 | 0.00276303291321 |
+----------------+--------------------+
| Add 10000 | 0.107849836349 |
+----------------+--------------------+
| Delete 10000 | 0.0282921791077 |
+----------------+--------------------+
| Add 100000 | 1.05564808846 |
+----------------+--------------------+
| Delete 100000 | 0.297379016876 |
+----------------+--------------------+
| Add 1000000 | 16.451695919 |
+----------------+--------------------+
| Delete 1000000 | 3.03641605377 |
+----------------+--------------------+
Relation ``dict:odict`` of creating and deleting.
::
+---------------------------+-----------+
| creating 1000 objects | 1:14.823 |
+---------------------------+-----------+
| deleting 1000 objects | 1:8.1497 |
+---------------------------+-----------+
| creating 10000 objects | 1:13.917 |
+---------------------------+-----------+
| deleting 10000 objects | 1:6.9598 |
+---------------------------+-----------+
| creating 100000 objects | 1:8.0947 |
+---------------------------+-----------+
| deleting 100000 objects | 1:5.7463 |
+---------------------------+-----------+
| creating 1000000 objects | 1:5.1797 |
+---------------------------+-----------+
| deleting 1000000 objects | 1:5.3781 |
+---------------------------+-----------+
Usage
-----
Import and create ordered dictionary.
::
>>> from odict import odict
>>> od = odict()
type conversion to ordinary ``dict``. This will fail.
::
>>> dict(odict([(1, 1)]))
{1: [nil, 1, nil]}
The reason for this is here -> http://bugs.python.org/issue1615701
The ``__init__`` function of ``dict`` checks wether arg is subclass of dict,
and ignores overwritten ``__getitem__`` & co if so.
This was fixed and later reverted due to behavioural problems with ``pickle``.
Use one of the following ways for type conversion.
::
>>> dict(odict([(1, 1)]).items())
{1: 1}
>>> odict([(1, 1)]).as_dict()
{1: 1}
It is possible to use abstract mixin class ``_odict`` to hook another dict base
implementation. This is useful i.e. when persisting to ZODB. Inheriting from
``dict`` and ``Persistent`` at the same time fails.
::
>>> from persistent.dict import PersistentDict
>>> class podict(_odict, PersistentDict):
... def _dict_impl(self):
... return PersistentDict
Requires
--------
-Python 2.4+
Changes
=======
Version 1.4.0
-------------
-Full test coverage
chaoflow, rnix, 2010-08-17
-Code cleanup and optimizing
chaoflow, rnix, 2010-08-17
Version 1.3.2
-------------
-Access ``dict`` API providing class via function ``_dict_impl()`` and
provide odict logic as abstract base class ``_odict``.
rnix, 2010-07-08
Version 1.3.1
-------------
-Add test for bool evaluation
rnix, 2010-04-21
Version 1.3.0
-------------
-Fix access to ``odict.lt`` and ``odict.lh`` properties. Now it's possible
to overwrite ``__setattr__`` and ``__getattr__`` on ``odict`` subclass
without hassle.
rnix, 2010-04-06
-Add ``sort`` function to odict.
rnix, 2010-03-03
Version 1.2.6
-------------
-Make ``odict`` serialize and deserialize properly
gogo, 2010-01-12
Version 1.2.5
-------------
-Add ``as_dict`` function. Supports type conversion to ordinary ``dict``.
rnix, 2009-12-19
-Add benchmark script
rnix, 2009-12-19
Version 1.2.4
-------------
-Do not check for ``key in self`` on ``__delitem__``, ``KeyError`` is raised
properly anyway. Huge Speedup!
rnix, jensens, 2009-12-18
Version 1.2.3
-------------
-Move tests to seperate file and make egg testable with
``python setup.py test``.
rnix, 2009-12-07
-improve ``lt`` and ``lh`` properties to make ``odict`` work with
``copy.deepcopy``.
rnix, 2009-12-07
Version 1.2.2
-------------
-Use try/except instead of ``__iter__`` in ``__setitem__`` to determine if
value was already set.
rnix, 2009-07-17
Version 1.2.1
-------------
-Add missing ``__len__`` and ``__contains__`` functions.
rnix, 2009-03-17
Version 1.2.0
-------------
-eggified
rnix, 2009-03-17
Version < 1.2
-------------
-http://code.activestate.com/recipes/498195/
bearophile, 2006-10-12
Contributors
============
-bearophile
-Robert Niederreiter <rnix@squarewave.at>
-Georg Bernhard <g.bernhard@akbild.ac.at>
-Florian Friesdorf <flo@chaoflow.net>
=====
Dictionary in which the *insertion* order of items is preserved (using an
internal double linked list). In this implementation replacing an existing
item keeps it at its original position.
Internal representation: values of the dict:
::
[pred_key, val, succ_key]
The sequence of elements uses as a double linked list. The ``links`` are dict
keys. ``self.lh`` and ``self.lt`` are the keys of first and last element
inseted in the odict. In a C reimplementation of this data structure, things
can be simplified (and speed up) a lot if given a value you can at the same
time find its key. With that, you can use normal C pointers.
Memory used (Python 2.5)
------------------------
-set(int): 28.2 bytes/element
-dict(int:None): 36.2 bytes/element
-odict(int:None): 102 bytes/element
Performance
-----------
When running the benchmark script, you get results similar to the one below
on recent common hardware.
Adding and deleting ``dict`` objects.
::
+----------------+--------------------+
| Add 1000 | 0.000653028488159 |
+----------------+--------------------+
| Delete 1000 | 0.000339031219482 |
+----------------+--------------------+
| Add 10000 | 0.00774908065796 |
+----------------+--------------------+
| Delete 10000 | 0.00406503677368 |
+----------------+--------------------+
| Add 100000 | 0.130412101746 |
+----------------+--------------------+
| Delete 100000 | 0.0517508983612 |
+----------------+--------------------+
| Add 1000000 | 3.17614817619 |
+----------------+--------------------+
| Delete 1000000 | 0.564585924149 |
+----------------+--------------------+
Adding and deleting ``odict`` objects.
::
+----------------+--------------------+
| Add 1000 | 0.0096800327301 |
+----------------+--------------------+
| Delete 1000 | 0.00276303291321 |
+----------------+--------------------+
| Add 10000 | 0.107849836349 |
+----------------+--------------------+
| Delete 10000 | 0.0282921791077 |
+----------------+--------------------+
| Add 100000 | 1.05564808846 |
+----------------+--------------------+
| Delete 100000 | 0.297379016876 |
+----------------+--------------------+
| Add 1000000 | 16.451695919 |
+----------------+--------------------+
| Delete 1000000 | 3.03641605377 |
+----------------+--------------------+
Relation ``dict:odict`` of creating and deleting.
::
+---------------------------+-----------+
| creating 1000 objects | 1:14.823 |
+---------------------------+-----------+
| deleting 1000 objects | 1:8.1497 |
+---------------------------+-----------+
| creating 10000 objects | 1:13.917 |
+---------------------------+-----------+
| deleting 10000 objects | 1:6.9598 |
+---------------------------+-----------+
| creating 100000 objects | 1:8.0947 |
+---------------------------+-----------+
| deleting 100000 objects | 1:5.7463 |
+---------------------------+-----------+
| creating 1000000 objects | 1:5.1797 |
+---------------------------+-----------+
| deleting 1000000 objects | 1:5.3781 |
+---------------------------+-----------+
Usage
-----
Import and create ordered dictionary.
::
>>> from odict import odict
>>> od = odict()
type conversion to ordinary ``dict``. This will fail.
::
>>> dict(odict([(1, 1)]))
{1: [nil, 1, nil]}
The reason for this is here -> http://bugs.python.org/issue1615701
The ``__init__`` function of ``dict`` checks wether arg is subclass of dict,
and ignores overwritten ``__getitem__`` & co if so.
This was fixed and later reverted due to behavioural problems with ``pickle``.
Use one of the following ways for type conversion.
::
>>> dict(odict([(1, 1)]).items())
{1: 1}
>>> odict([(1, 1)]).as_dict()
{1: 1}
It is possible to use abstract mixin class ``_odict`` to hook another dict base
implementation. This is useful i.e. when persisting to ZODB. Inheriting from
``dict`` and ``Persistent`` at the same time fails.
::
>>> from persistent.dict import PersistentDict
>>> class podict(_odict, PersistentDict):
... def _dict_impl(self):
... return PersistentDict
Requires
--------
-Python 2.4+
Changes
=======
Version 1.4.0
-------------
-Full test coverage
chaoflow, rnix, 2010-08-17
-Code cleanup and optimizing
chaoflow, rnix, 2010-08-17
Version 1.3.2
-------------
-Access ``dict`` API providing class via function ``_dict_impl()`` and
provide odict logic as abstract base class ``_odict``.
rnix, 2010-07-08
Version 1.3.1
-------------
-Add test for bool evaluation
rnix, 2010-04-21
Version 1.3.0
-------------
-Fix access to ``odict.lt`` and ``odict.lh`` properties. Now it's possible
to overwrite ``__setattr__`` and ``__getattr__`` on ``odict`` subclass
without hassle.
rnix, 2010-04-06
-Add ``sort`` function to odict.
rnix, 2010-03-03
Version 1.2.6
-------------
-Make ``odict`` serialize and deserialize properly
gogo, 2010-01-12
Version 1.2.5
-------------
-Add ``as_dict`` function. Supports type conversion to ordinary ``dict``.
rnix, 2009-12-19
-Add benchmark script
rnix, 2009-12-19
Version 1.2.4
-------------
-Do not check for ``key in self`` on ``__delitem__``, ``KeyError`` is raised
properly anyway. Huge Speedup!
rnix, jensens, 2009-12-18
Version 1.2.3
-------------
-Move tests to seperate file and make egg testable with
``python setup.py test``.
rnix, 2009-12-07
-improve ``lt`` and ``lh`` properties to make ``odict`` work with
``copy.deepcopy``.
rnix, 2009-12-07
Version 1.2.2
-------------
-Use try/except instead of ``__iter__`` in ``__setitem__`` to determine if
value was already set.
rnix, 2009-07-17
Version 1.2.1
-------------
-Add missing ``__len__`` and ``__contains__`` functions.
rnix, 2009-03-17
Version 1.2.0
-------------
-eggified
rnix, 2009-03-17
Version < 1.2
-------------
-http://code.activestate.com/recipes/498195/
bearophile, 2006-10-12
Contributors
============
-bearophile
-Robert Niederreiter <rnix@squarewave.at>
-Georg Bernhard <g.bernhard@akbild.ac.at>
-Florian Friesdorf <flo@chaoflow.net>
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
odict-1.4.0.tar.gz
(6.3 kB
view hashes)