Update PEP based on latest version of recipe, based on integration testing, and based on newsgroup feedback.

This commit is contained in:
Raymond Hettinger 2009-02-27 04:32:11 +00:00
parent 879ca8008b
commit 4715116df7
1 changed files with 57 additions and 16 deletions

View File

@ -143,22 +143,19 @@ constructor?
This behavior is consistent with existing implementations in
Python, the PHP array and the hashmap in Ruby 1.9.
Why is there no ``odict.insert()``?
There are few situations where you really want to insert a key at
a specified index. To avoid API complication, the proposed
solution for this situation is creating a list of items,
manipulating that and converting it back into an odict:
>>> d = odict([('a', 42), ('b', 23), ('c', 19)])
>>> l = d.items()
>>> l.insert(1, ('x', 0))
>>> odict(l)
collections.odict([('a', 42), ('x', 0), ('b', 23), ('c', 19)])
Is the ordered dict a dict subclass?
Is the ordered dict a dict subclass? Why?
Yes. Like ``defaultdict``, ``odict`` subclasses ``dict``.
Being a dict subclass confers speed upon methods that aren't overridden
like ``__getitem__`` and ``__len__``. Also, being a dict gives the
most utility with tools that were expecting regular dicts (like the
json module).
Do any limitations arise from subclassing dict?
Yes. Since the API for dicts is different in Py2.x and Py3.x, the
odict API must also be different (i.e. Py2.6 needs to override
iterkeys, itervalues, and iteritems).
Does ``odict.popitem()`` return a particular key/value pair?
@ -166,8 +163,8 @@ Does ``odict.popitem()`` return a particular key/value pair?
corresponding value. This corresponds to the usual LIFO behavior
exhibited by traditional push/pop pairs. It is semantically
equivalent to ``k=list(od)[-1]; v=od[k]; del od[k]; return (k,v)``.
The actual implementation is more efficient. It is O(n log n)
on the first call, any successive calls are O(1).
The actual implementation is more efficient and pops directly
off of a sorted list of keys.
Does odict support indexing, slicing, and whatnot?
@ -184,6 +181,50 @@ Does odict support alternate sort orders such as alphabetical?
dbm) is likely a better fit. It would be a mistake to try to be all
things to all users.
How well does odict work with the json module and PyYAML?
For json, the good news is that json's encoder respects odict's iteration order:
>>> items = [('one', 1), ('two', 2), ('three',3), ('four',4), ('five',5)]
>>> json.dumps(OrderedDict(items))
'{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}'
The bad news is that the object_hook for json decoders will pass in an
already built dictionary so that the order is lost before the object
hook sees it:
>>> jtext = '{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}'
>>> json.loads(jtext, object_hook=OrderedDict)
OrderedDict({u'four': 4, u'three': 3, u'five': 5, u'two': 2, u'one': 1})
For PyYAML, a full round-trip is problem free:
>>> ytext = yaml.dump(OrderedDict(items))
>>> print ytext
!!python/object/apply:collections.OrderedDict
- - [one, 1]
- [two, 2]
- [three, 3]
- [four, 4]
- [five, 5]
>>> yaml.load(ytext)
OrderedDict({'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5})
How does odict handle equality testing?
Being a dict, one might expect equality tests to not care about order. For
an odict to dict comparison, this would be a necessity and it's probably
not wise to silently switch comparison modes based on the input types.
Also, some third-party tools that expect dict inputs may also expect the
comparison to not care about order. Accordingly, we decided to punt and
let the usual dict equality testing run without reference to internal
ordering. This should be documented clearly since different people will
have different expectations. If a use case does arise, it's not hard to
explicitly craft an order based comparison:
``list(od1.items())==list(od2.items())``.
Reference Implementation
========================