[Python-Dev] multidict API (original) (raw)

Barry Warsaw barry at python.org
Fri Mar 10 22:05:40 CET 2006


On Fri, 2006-03-10 at 11:25 -0600, Ian Bicking wrote:

I'm not really making any actionable proposal here, so maybe this is off-topic; if so, sorry.

Back during the defaultdict discussion I proposed a multidict object (http://mail.python.org/pipermail/python-dev/2006-February/061264.html) -- right now I need to implement one to represent web form submissions. It would also be ordered in that case.

FWIW, the email package's Message class implements something similar in its mapping API, to represent message headers. I'm not saying that it's a good general approach to the problem, but I do think the way we solved it works well for Messages. The implementation is also probably not very good for general purposes, since it can involve linear searches of lists, but for Messages, which don't typically have that many headers, I think it's fine.

Messages keep track of the order in which the headers are added, and you may have multiple values for each header. If you delete a header and re-add it, it gets added to the end. So iterating over the headers gives you each header in order, including duplicates. getitem() however will return only one of those headers; which exactly you get is technically undefined. get() has the same semantics.

There's a new get_all() method that takes a key and returns a list of all the values for that key (header). delitem() removes all matching keys.

* Does getitem return a list of all matching keys (never a KeyError, though possibly returning []), or does it return the first matching key?

See above -- it returns one matching key, but the spec doesn't specify which one (see the implementation for the obvious answer ;). One other semantic difference with Messages is that getitem() on a missing header returns None -- it does not raise a KeyError. Practicality beats purity.

* Either way, I assume there will be another method, like getfirst or getall, that will present the other choice. What would it be named? Should it have a default?

In Message, it's called get_all() and it does take an optional default, just like get().

* Should there be a method to get a single value, that implicitly asserts that there is only one matching key?

Message doesn't have this.

* Should the default for .get() be None, or something else?

Message.get() defaults to None.

* Does setitem overwrite any or all values with matching keys?

Message's setitem() appends the header (there's a separate add_header() method that takes a bunch of arguments specific to email headers) but it does not overwrite any existing header. The idiom used to replace a header is usually:

del msg['some-header'] msg['Some-Header'] = 'Wizzy Mailerified'

Oh yeah, keys are case-preserving but case-insensitive because in email messages 'Some-Header: Foo' is the same as 'some-header: Foo', but we want to be as idempotent as possible.

* If so, there should be another method like .add(key, value) which does not overwrite. Or, if setitem does not overwrite, then there should be a method that does.

Message.replace_header() preserves header order, and it replaces the value for the first header found.

* Does delitem raise a KeyError if the key is not found?

For Message, the answer is "no".

* Does .keys() return all unique keys, or all keys in order (meaning a key may show up more than once in the list)?

Message.keys() returns them in order. Likewise .values() and .items().

I really could go either way on all of these questions, though I think there's constraints -- answer one of the questions and another becomes obvious. But you can answer them in whatever order you want.

Cool, thanks! For simplicity, I've answered them in the order they were asked, just like Message would. :)

-Barry

-------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 309 bytes Desc: This is a digitally signed message part Url : http://mail.python.org/pipermail/python-dev/attachments/20060310/e1b69e06/attachment.pgp



More information about the Python-Dev mailing list