469,330 Members | 1,284 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,330 developers. It's quick & easy.

Why are there no ordered dictionaries?

This is probably a FAQ, but I dare to ask it nevertheless since I
haven't found a satisfying answer yet: Why isn't there an "ordered
dictionary" class at least in the standard list? Time and again I am
missing that feature. Maybe there is something wrong with my programming
style, but I rather think it is generally useful.

I fully agree with the following posting where somebody complains why so
very basic and useful things are not part of the standard library:
http://groups.google.com/group/comp....52d2f771a49857

Are there plans to get it into the standard lib sometime?

-- Christoph
Nov 22 '05
210 8909
Christoph Zwerschke wrote:
I will assume that d has is a Foord/Larosa ordered dict with "sequence"
attribute in the following.

Then, with other words,

d.keys[:] = newkeyseq

should do the same as:

d.sequence = newkeyseq


At least in the case where newkeyseq is a permutation of d.sequence.

Otherwise, it should behave like the given implementation for setting
slices, i.e.

- if newkeyseq has duplicate elements, an exception should be raised.
- if newkeyseq has elements not in d.sequence, then the dictionary
should be updated with corresponding None values
- if d.sequence has elements not in newkeyseq then these elements should
be deleted from the dictionary

-- Christoph
Nov 27 '05 #201
Bengt Richter schrieb:
OTOH,
>>> {}[:]
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: unhashable type
I.e., slices are not valid keys for ordinary dicts, and slices tie in
very well with the ordered aspect of ordered dicts, so that's an
argument for permitting it via the indexing syntax, not just items[:]
or items()[:] which have related but not identical semantics.


I see it like that. BTW, the above error message is pretty bad.
I wonder who is going to use it for what.


I think re-ordering will be a very rare use case anyway and slicing even
more. As a use case, I think of something like mixing different
configuration files and default configuration parameters, while trying
to keep a certain order of parameters and parameters blocks.

-- Christoph
Nov 27 '05 #202
Note that I've done two things with the Foord/Larosa dict. ;-)

I've implemented slicing, including slice assignment and deletion. I've
also 'hidden' ``sequence``, but you can pass arguments to keys, values
and items.

I've done a second (experimental) implementation of a custom keys
object. This is effectively the managed list - which you can call as a
method or mutate in place. You can't delete members from 'keys' but you
can do slice assignment so long as the sequence you're replacing is the
same length (and is a re -ordering of the set being replaced).

I'll post it on Monday, and if people like it I'll complete it.

All the best,
Fuzzyman
http://www.voidspace.org.uk/python/index.shtml

Nov 27 '05 #203
On Sun, 27 Nov 2005 12:00:23 +0100, Christoph Zwerschke <ci**@online.de> wrote:
Bengt Richter wrote:
d.keys[:] = newkeyseq
Do you really mean just re-ordering the keys without a corresponding reording of values??
That would be a weird renaming of all values. Or do you means that any key should still
retrieve the same value as before if used as d[key]? In which case the values must undergo
the same permutation as the keys. I.e., you are assuming key->value pairings remain stable
through any key reorderings?


Since it is considered as being a dictionary in the first place, the
key->value pairings should of course stay stable. In the usual
implementation based on an ordinary dictionary with an additional key
list ("sequence" in the Foord/Larosa and "_keys" in the Bejamin/Winter
implementation), you would only set the key list, since the value list
is generated dynamically. But if your implementation keeps internal
values or items lists, these need to be adjusted as well.

I will assume that d has is a Foord/Larosa ordered dict with "sequence"
attribute in the following.

Then, with other words,

d.keys[:] = newkeyseq

should do the same as:

d.sequence = newkeyseq
Exactly what, though? should e.g.
d.keys[3] = newk3
mean (not a suggested implementation, just to define semantics)
keys = d.keys()
if newk3 in keys and keys.index(newk3)!=3:
raise ValueError,'Attempt to introduce duplicate key'
items = d.items()
items[3] = (newk3, items[3][1])
d.clear()
d.update(items)


Yes, that would be the correct semantics. Of course this should not be
the real implementation and use KeyError instead of ValueError. With
other words,

d.keys[i] = newkey

sould be the same as:

if d.sequence[i] != newkey:
if newkey in d.sequence:
raise KeyError,'Attempt to introduce duplicate key'
else:
d.sequence[i] = newkey
This would allow what you might call renaming in place.
Similarly
d.keys[i:j] = newkeysij
might have the semantics of
keys = d.keys()
outside = set(keys[:i])+set(keys[j:])
if outside & set(newkeysij) or len(newkeysij) != len(set(newkeysij)):
raise ValueError,'Attempt to introduce duplicate key(s)'
items = d.items()
items[i:j] = [(k, items[kx+i][1]) for kx,k in enumerate(newkeysij)]
d.clear()
d.update(items)

Is this what is desired?


Not quite, because it does not preserve the key->value pairings (see
above) and it would behave strangely or raise an exception if the new
slice is larger. The following code would do:


keys = d.keys()
outside = set(keys[:i])|set(keys[j:])
if outside & set(newkeysij) or len(newkeysij) != len(set(newkeysij)):
raise ValueError,'Attempt to introduce duplicate key(s)'
items = d.items()
items[i:j] = [(k, d.get(k, None)) for k in newkeysij]
d.clear()
d.update(items)

(Note that there was a bug in the second line. You cannot add sets.) Oops, thinking about adding dicts ;-)

Again, this would be equivalent to:

seq = d.sequence
newseq = seq[:]
newseq[i:j] = newkeysij
if len(newseq) != len(set(newseq)):
raise KeyError,'Attempt to introduce duplicate key(s)'
for k in set(seq[i:j]) - set(newkeysij):
del d[k]
for k in set(newkeysij) - set(seq[i:j]):
d[k] = None
d.sequence = newseq
You don't keep track of the item lists, they need to be built on every
occasion.


That depends on how you implement ;-)


Ok, I was thinking of the usual implementations.
Back from holiday, so maybe I'll hack something out.


Let us know when you have something to check out.

Maybe Fuzzyman can make some moderate improvements to the existing
odict.py, and you can do something more "radical". Then we have two
"reference implementations" and can compare how they prove regarding
performance and usability.

My code so far is a kludge to get functionality. Perhaps we can arrive at
a spec by doing some TDD. My current kludge passes these tests
(run by py.test which I downloaded from the pypy project site and made
work (apparanently ;-) with IIRC a .pth file to point to py where I
expanded the zip, and a cmd file to kick of python running py.test,
and I think that was all there was. As you can see, it is super easy to define
tests. If you want to try it, I think I can retrace my steps and describe
the way I set it up (for windows NT) in a few turgid run-on paragraphs ;-)
Maybe I'll get around to writing a downloading/checking/installing script
for it, with a few interactive are-you-sure?'s and file tree placement options etc.

I'm calling it a Creordict for now -- Created-order-dict.
Here are the tests so far. Do you want to add some to refine what's supposed to
happen. You may want to look at test_items, test_keys, test_values
as those are the ones that provide d.items(), d.items[i], d.items[i:j]
style accesses, with assign, eval, and del available for the latter two.
also test___getitem__ for d[i] => value normal key access vs
d[i:j] => another Creordict instance. Let me know what's missing.
I'm not sure how this list-based dict object will work out, but it's
a subclass of list, not of dict. ;-)

Some def test_usecase_xx(): ... definitions might be nice.
I am running py.test on windows NT. I din't compile anything,
I just cobbled afew things together.

----< test_creordict.py >----------------------------------------------
# test_creordict.py
# XXX assoclist.py ?? cf. scheme assv using == (eq<->is, eqv<->==, equal<->deep== ???)
# Tests for creordict.py -- a dictionary object which keeps items in creation time order.
#
# XXX boilerplate bokr AT oz DOT net
from py.test import raises
import py

from creordict import Creordict

def test_sanity():
d = Creordict()
assert d.keys() == []
assert d.values() == []
assert d.items() == []
assert d == d
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
assert repr(d) == "Creordict([('a', 0), ('b', 100), ('c', 200), ('d', 300), ('e', 400)])"
assert d.keys() == ['a', 'b', 'c', 'd', 'e']
assert d.values() == [0, 100, 200, 300, 400]
assert d.items() == [('a', 0), ('b', 100), ('c', 200), ('d', 300), ('e', 400)]
def test___init__():
d = Creordict()
assert d.keys() == []
assert d.values() == []
assert d.items() == []
assert d == d
assert d._index == {}
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
assert repr(d) == "Creordict(%r)"% d.items()
assert d.keys() == ['a', 'b', 'c', 'd', 'e']
assert d.values() == [0, 100, 200, 300, 400]
assert d.items() == [('a', 0), ('b', 100), ('c', 200), ('d', 300), ('e', 400)]
assert d._index == {'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3}

def test___contains__():
d = Creordict([('a', 1)])
assert 'a' in d
assert (4 in d) == False

def test___eq__():
d = Creordict([('a', 1)])
assert d == d
raises(TypeError, "d == {}")
assert d != Creordict([('b', 1)])

def test___cmp__():
d = Creordict([('a', 1)])
assert cmp(d, d) == 0
raises(TypeError, "cmp(d, {})")

def mkresult(s, **kw):
return Creordict((k, kw.get(k, k in 'abcdef' and 'abcdef'.index(k)*100)) for k in s)

def test___delitem__():
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
print mkresult('abcde')
assert d == mkresult('abcde')
ditems = d.items()
print d['b']
print d.items()
print d._index
print d._index['b']
del d['b']
assert d == mkresult('acde')
del d['a']
assert d == mkresult('cde')
del d['e']
assert d == mkresult('cd')
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
del d[1:3]
assert d == mkresult('ade')
del d[:1]
assert d == mkresult('de')
del d[-1:]
assert d == mkresult('d')

def test___repr__():
assert repr(Creordict()) == 'Creordict([])'
raises(TypeError, "Creordict({1: 1})")
d = Creordict(((1, 3), (3, 2), (2, 1)))
assert repr(d) =='Creordict([(1, 3), (3, 2), (2, 1)])'

def test___setitem__():
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
print mkresult('abcde')
assert d == mkresult('abcde')
d['b'] = 101
assert d == mkresult('abcde', b=101)
d['e'] = 401
assert d == mkresult('abcde', b=101, e=401)

def test___getitem__():
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
assert d == mkresult('abcde')
items = d.items()
for k,v in items:
assert d[k]==v
raises(KeyError, "d['f']")

def test___getslice__():
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
assert d[2:4] == mkresult('cd')
assert d[ :4] == mkresult('abcd')
assert d[2: ] == mkresult('cde')
assert d[ : ] == mkresult('abcde')
assert d[0:0] == mkresult('')

def test___add__():
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
assert d+d == d
assert d + Creordict([('f', 500)]) == mkresult('abcdef')

def test_reverse():
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
d.reverse()
assert d == mkresult('edcba')

def test_insert():
d = Creordict([(k,i*100) for i,k in enumerate('abc')])
d.insert(1, ('x', 101))
assert d == mkresult('axbc', x=101, b=100, c=200)

def test_get():
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
assert d == mkresult('abcde')
items = d.items()
for k,v in items:
assert d.get(k)==v
assert d.get(k+'1') is None
assert d.get(k+'1', v) == v
raises(KeyError, "d['f']")

def test_copy():
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
assert d == d.copy()

def test_items():
assert Creordict().items() == []
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
assert d.items() == [(k,i*100) for i,k in enumerate('abcde')]
assert d.items[:] == [(k,i*100) for i,k in enumerate('abcde')]
assert d.items[2:4] == [(k,i*100) for i,k in enumerate('abcde')][2:4]
d.items[2:4] = []
assert d == mkresult('abe')
d.items[1] = ('x', 'replaces b')
assert d == mkresult('axe', x='replaces b')
def test_keys():
assert Creordict().keys() == []
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
assert d.keys() == list('abcde')
assert d.keys[:] == list('abcde')
assert d.keys[2:4] == list('cd')
assert d.keys[1] == 'b'
assert d.keys[-1] == 'e'
d.keys[2:4] = ['x', 'y']
assert d == mkresult('abxye', x=200, y=300)
del d.keys[-1]
assert d == mkresult('abxy', x=200, y=300)
keys = d.keys()
keys[0], keys[-1] = keys[-1], keys[0] # swap end keys
d.keys[:]=keys
assert d == mkresult('ybxa', x=200, y=0, a=300) # a and y value associations swapped ;-)

def test_values():
assert Creordict().values() == []
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
assert d.values() == [i*100 for i,k in enumerate('abcde')]
assert d.values[:] == [i*100 for i,k in enumerate('abcde')]
assert d.values[2:4] == d[2:4].values()
assert d.values[1] == d.values()[1]
assert d.values[-1] == d.values()[-1]
d.values[2:4] = ['v2', 'v3']
assert d == mkresult('abcde', c='v2', d='v3')
del d.values[-1]
assert d == mkresult('abcd', c='v2', d='v3')
values = d.values()
values[0], values[-1] = values[-1], values[0] # swap end values
d.values[:]=values
assert d == mkresult('abcd', c='v2', d=0, a='v3') # a and y value associations swapped ;-)

def test_iteritems():
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
itd = d.iteritems()
assert type(itd) == type(iter([]))
assert list(itd) == d.items()

def test_len():
d = Creordict()
assert len(d) == 0
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
assert len(d) == 5

def test_has_key():
d = Creordict(((1, 3), (3, 2), (2, 1)))
assert d.has_key(1) is True
assert d.has_key(4) is False

def test_iterkeys():
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
itd = d.iterkeys()
assert type(itd) == type(x for x in [])
assert list(itd) == d.keys()

def test_itervalues():
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
itd = d.itervalues()
assert type(itd) == type(x for x in [])
assert list(itd) == d.values()

def test_clear():
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
d.clear()
assert d.items() == []
assert d.keys() == []
assert d.values() == []

def test_pop():
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
assert d.pop('e') == 400
assert d.pop('b') == 100
assert d.pop('a') == 0
assert d == mkresult('cd')

def test_popitem():
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
assert d.popitem() == ('e', 400)
assert d.popitem() == ('d', 300)
assert d.popitem() == ('c', 200)
assert d == mkresult('ab')

def test_setdefault():
d = Creordict([(k,i*100) for i,k in enumerate('abcde')])
assert d.setdefault('c', 'cee') == 200
assert d.setdefault('g') is None
assert d == mkresult('abcdeg', g=None)
assert d.setdefault('h', 'eightch') == 'eightch'
assert d == mkresult('abcdegh', g=None, h='eightch')

def test_update():
d = Creordict()
assert d == mkresult('')
d.update([(k,i*100) for i,k in enumerate('abcde')])
assert d == mkresult('abcde')
raises(TypeError, "d.update({'f': 500})")
d.update([('f', 500), ('b',101)])
assert d == mkresult('abcdef', b=101)
raises(ValueError, "d.update([('broken',)])")

-----------------------------------------------------------------------

Regards,
Bengt Richter
Nov 29 '05 #204
I had the same idea to create a py.test to verify and compare various
implementations. The doctests in odict.py are nice, but you can't use
them for this purpose and they may not test enough. It would be also
good to have something for testing and comparing performance.

-- Christoph
Nov 29 '05 #205
On Tue, 29 Nov 2005 23:30:45 +0100, Christoph Zwerschke <ci**@online.de> wrote:
I had the same idea to create a py.test to verify and compare various
implementations. The doctests in odict.py are nice, but you can't use
them for this purpose and they may not test enough. It would be also
good to have something for testing and comparing performance.

Well, the previous post test file just grew to make a simple check for various
aspects, so it's not super clean. I just grepped for defs in the implementation
and bulk appended "test_" to make an empty starting point. Then I just filled
in tests after a preliminary sanity check test. But there are some things
that could still accidentally be inherited from the base class when builtin
utility functions are called on the dict object. Also there's a lot of cut-paste
duplication an no full explorations of corner cases. There's neat generator-based
test driving with different parameters that I didn't take advantage of,
etc. etc.

I should really read the py test docs and learn to use it
better if I am going to use it. But anyway, it's a q&d hack to show and
sanity-check different usages. The semantics of assigning slices
to d.keys[i:j] and d.values[i:j] are kind of tricky when the size changes
and/or key names match or don't match in various ways, or the incoming
data represents collapsing redundant keys that are legal sequential assignment
overrides but change the size, etc.

One could add keyword args to the constructor to vary key eq and cmp used
on keys to determine "key collisions" between e.g. tuple keys and also for
sort. You could even allow partially non-hashable keys that way if you got tricky.
But maybe this is getting too tricky ;-)

I'll make some simple mods to the test to allow applying it to arbitrary
candidate implementations with different names and directory locations, so
I can try it on odict.py and other versions. But are the semantics right?

Doctest is handy, and in some ways I like examples showing up in the help docs,
but maybe help should take a keyword arg to select showing them (and some other
things too perhaps. A brief version excluding a lot of inheritance for classes
might be nice. Or a pattern for method and class var inclusion.

But I like the separation of the py.test tests with no need to mod the original.
Where next? This ordered dict thing is kind of a side-track from a side-track for me ;-)

Regards,
Bengt Richter
Nov 30 '05 #206

Christoph Zwerschke wrote:

Hello Christoph,
I think re-ordering will be a very rare use case anyway and slicing even
more. As a use case, I think of something like mixing different
configuration files and default configuration parameters, while trying
to keep a certain order of parameters and parameters blocks.

In actual fact - being able to *reorder* the dictionary is the main way
I use this dictionary.

All the best,

Fuzzyman
http://www.voidspace.org.uk/python/index.shtml
-- Christoph


Dec 1 '05 #207
Hmmm... it would be interesting to see if these tests can be used with
odict.

The odict implementation now has full functionality by the way.

Optimisations to follow and maybe a few *minor* changes.

Fuzzyman
http://www.voidspace.org.uk/python/index.shtml

Dec 1 '05 #208
> The semantics of assigning slices
to d.keys[i:j] and d.values[i:j] are kind of tricky when the size changes
and/or key names match or don't match in various ways, or the incoming
data represents collapsing redundant keys that are legal sequential assignment
overrides but change the size, etc.

I have come against the same problem with slice assignment, when doing
odict. :-)
Allowing the size to change prevents a useful optimisation - but I
dislike *preventing* programmers from doing things.

All the best,

Fuzzyman
http://www.voidspace.org.uk/python/index.shtml

Regards,
Bengt Richter


Dec 1 '05 #209
On 1 Dec 2005 03:53:27 -0800, "Fuzzyman" <fu******@gmail.com> wrote:
Hmmm... it would be interesting to see if these tests can be used with
odict. I assume you are referring to the pytest tests I posted, though I would
need some of the context you snipped to me more sure ;-)

Anyway, with some changes[1], they can.

The odict implementation now has full functionality by the way.
The one at
http://www.voidspace.org.uk/cgi-bin/...?file=odict.py
? It seems to be unchanged.

Optimisations to follow and maybe a few *minor* changes.

Anyway, test of the above results in:

C:\UTIL\\..\py.test test
============================= test process starts =============================
testing-mode: inprocess
executable: d:\python-2.4b1\mingw\python24.exe (2.4.0-beta-1)
using py lib: D:\bpy24\py-0.8.0-alpha2\py <rev unknown>

test\test_odicts.py[28] FF...FF..FFFF..FFF..........
test\test_odicts_candidate.py[0]

__________________________________________________ _____________________________
___________________________ entrypoint: test_sanity ___________________________

def test_sanity():
d = CandidateDict()
assert d.keys() == []
assert d.values() == []
assert d.items() == []
assert d == d
d = CandidateDict([(k,i*100) for i,k in enumerate('abcde')])
E assert repr(d) == "%s([('a', 0), ('b', 100), ('c', 200), ('d', 300), ('e', 400)])"%Can
dateDict.__name__ assert "{'a': 0, 'b': 100, 'c': 200, 'd': 300, 'e': 400}" == ("%s([('a', 0), ('b', 100 ('c', 200), ('d', 300), ('e', 400)])" % CandidateDict.__name__)
+ where "{'a': 0, 'b': 100, 'c': 200, 'd': 300, 'e': 400}" = repr({'a': 0, 'b': 100,
c': 200, 'd': 300, 'e': 400})

[C:\pywk\ut\test\test_odicts.py:19]
__________________________________________________ _____________________________
Apparently you are still using plain dict repr format, not a format that could (ideally) be exec'd
to reconstitute the thing repr'd.
from clp.odict import OrderedDict as CandidateDict
CandidateDict.__name__ 'OrderedDict' repr(CandidateDict()) '{}'

vs
from ut.creordict import Creordict as CandidateDict
CandidateDict.__name__ 'Creordict' repr(CandidateDict()) 'Creordict([])'

Since the test uses CandidateDict.__name__, it should work either way.

__________________________ entrypoint: test___init__ __________________________

def test___init__():
d = CandidateDict()
assert d.keys() == []
assert d.values() == []
assert d.items() == []
assert d == d
d = CandidateDict([(k,i*100) for i,k in enumerate('abcde')])
E assert repr(d) == "%s(%r)"% (CandidateDict.__name__, d.items()) assert "{'a': 0, 'b': 100, 'c': 200, 'd': 300, 'e': 400}" == ('%s(%r)' % ('OrderedDict [('a', 0), ('b', 100), ('c', 200), ('d', 300), ('e', 400)]))
+ where "{'a': 0, 'b': 100, 'c': 200, 'd': 300, 'e': 400}" = repr({'a': 0, 'b': 100,
c': 200, 'd': 300, 'e': 400})

[C:\pywk\ut\test\test_odicts.py:32]
__________________________________________________ _____________________________
(Duplicate from test_sanity)

________________________ entrypoint: test___delitem__ _________________________

def test___delitem__():
d = CandidateDict([(k,i*100) for i,k in enumerate('abcde')])
print mkresult('abcde')
assert d == mkresult('abcde')
ditems = d.items()
print d['b']
print d.items()
del d['b']
assert d == mkresult('acde')
del d['a']
assert d == mkresult('cde')
del d['e']
assert d == mkresult('cd')
d = CandidateDict([(k,i*100) for i,k in enumerate('abcde')]) del d[1:3]
[C:\pywk\ut\test\test_odicts.py:70]
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

def __delitem__(self, key):
""" d = OrderedDict(((1, 3), (3, 2), (2, 1)))
del d[3]
d {1: 3, 2: 1} del d[3]

Traceback (most recent call last):
KeyError: 3
"""
# do the dict.__delitem__ *first* as it raises
# the more appropriate error
E dict.__delitem__(self, key) TypeError: unhashable type
[c:\pywk\clp\odict.py:137]
- - - - - - - - - - - test___delitem__: recorded stdout - - - - - - - - - - -
{'a': 0, 'b': 100, 'c': 200, 'd': 300, 'e': 400}
100
[('a', 0), ('b', 100), ('c', 200), ('d', 300), ('e', 400)]

__________________________________________________ _____________________________
You don't appear to accept slice operation syntax directly on the instance

__________________________ entrypoint: test___repr__ __________________________

def test___repr__():
E assert repr(CandidateDict()) == '%s([])'%CandidateDict.__name__ assert '{}' == ('%s([])' % CandidateDict.__name__) + where '{}' = repr({})
+ where {} = CandidateDict()

[C:\pywk\ut\test\test_odicts.py:78]
__________________________________________________ _____________________________
________________________ entrypoint: test___getslice__ ________________________

def test___getslice__():
d = CandidateDict([(k,i*100) for i,k in enumerate('abcde')])
E assert d[2:4] == mkresult('cd') TypeError: unhashable type
[C:\pywk\ut\test\test_odicts.py:102]
__________________________________________________ _____________________________
Again, no slice op

__________________________ entrypoint: test___add__ ___________________________

def test___add__():
d = CandidateDict([(k,i*100) for i,k in enumerate('abcde')])
E assert d+d == d TypeError: unsupported operand type(s) for +: 'OrderedDict' and 'OrderedDict'
[C:\pywk\ut\test\test_odicts.py:110]
__________________________________________________ _____________________________
No addition defined on OrderedDicts?

__________________________ entrypoint: test_reverse ___________________________

def test_reverse():
d = CandidateDict([(k,i*100) for i,k in enumerate('abcde')])
E d.reverse() AttributeError: 'OrderedDict' object has no attribute 'reverse'
[C:\pywk\ut\test\test_odicts.py:115]
__________________________________________________ _____________________________
No reverse

___________________________ entrypoint: test_insert ___________________________

def test_insert():
d = CandidateDict([(k,i*100) for i,k in enumerate('abc')])
E d.insert(1, ('x', 101)) AttributeError: 'OrderedDict' object has no attribute 'insert'
[C:\pywk\ut\test\test_odicts.py:120]
__________________________________________________ _____________________________
No insert

___________________________ entrypoint: test_items ____________________________

def test_items():
assert CandidateDict().items() == []
d = CandidateDict([(k,i*100) for i,k in enumerate('abcde')])
assert d.items() == [(k,i*100) for i,k in enumerate('abcde')]
E assert d.items[:] == [(k,i*100) for i,k in enumerate('abcde')] TypeError: unsubscriptable object
[C:\pywk\ut\test\test_odicts.py:141]
__________________________________________________ _____________________________
Only d.items() ?

____________________________ entrypoint: test_keys ____________________________

def test_keys():
assert CandidateDict().keys() == []
d = CandidateDict([(k,i*100) for i,k in enumerate('abcde')])
assert d.keys() == list('abcde')
E assert d.keys[:] == list('abcde') TypeError: unsubscriptable object
[C:\pywk\ut\test\test_odicts.py:153]
__________________________________________________ _____________________________
Only d.keys() ?

___________________________ entrypoint: test_values ___________________________

def test_values():
assert CandidateDict().values() == []
d = CandidateDict([(k,i*100) for i,k in enumerate('abcde')])
assert d.values() == [i*100 for i,k in enumerate('abcde')]
E assert d.values[:] == [i*100 for i,k in enumerate('abcde')] TypeError: unsubscriptable object
[C:\pywk\ut\test\test_odicts.py:170]
__________________________________________________ _____________________________
Only d.values() ?

============ tests finished: 17 passed, 11 failed in 1.36 seconds =============
[1] I changed the tests to use a CandidateDict alias, and eliminated a couple of checks
on internal state, so as to allow different implementations to be tested, using
CandidateDict.__name__ to synthesize alternate expected representation strings.

I made the test selectable if run interactively instead of directly via pytest:

[17:43] C:\pywk\ut>py24 test\test_odicts.py
Enter selection [1..2] (q to do nothing)
for importing candidate odicts
1: from ut.creordict import Creordict as CandidateDict
2: from clp.odict import OrderedDict as CandidateDict 1


"from ut.creordict import Creordict as CandidateDict"

is selected. Type "Yes" exactly (w/o quotes) to accept: Yes
============================= test process starts =============================
testing-mode: inprocess
executable: d:\python-2.4b1\mingw\python24.exe (2.4.0-beta-1)
using py lib: D:\bpy24\py-0.8.0-alpha2\py <rev unknown>

test\test_odicts.py[28] ............................

================== tests finished: 28 passed in 1.03 seconds ==================

Not sure they way I did it is a good idea, but anyway I can just add a little
boilerplate at the bottom of a test and a text file with the choices (which are
one-line sources that get written to test_... so the test can do from test_... import CandidateDict
and have the chosen class by the name it uses for both.

Regards,
Bengt Richter
Dec 2 '05 #210
On 1 Dec 2005 01:48:56 -0800, "Fuzzyman" <fu******@gmail.com> wrote:

Christoph Zwerschke wrote:


Hello Christoph,
I think re-ordering will be a very rare use case anyway and slicing even
more. As a use case, I think of something like mixing different
configuration files and default configuration parameters, while trying
to keep a certain order of parameters and parameters blocks.


In actual fact - being able to *reorder* the dictionary is the main way
I use this dictionary.

Curious as to usage patterns
1) how many instances created, deleted
2) how many elements in an instance min, max?
3) how often updated?
3a) just ordering, no value or size change?
3b) just value change, no order or size change?
3c) changes involving size?
4) proportions of read vs write/delete/reorder accesses?

Regards,
Bengt Richter
Dec 2 '05 #211

This discussion thread is closed

Replies have been disabled for this discussion.

By using this site, you agree to our Privacy Policy and Terms of Use.