[Python-ideas] Let's be more orderly!

Steven D'Aprano steve at pearwood.info
Thu May 16 05:16:01 CEST 2013


On 16/05/13 07:27, Andrew Barnert wrote:

>> The first thing you think of is, "Oh, I just need to use an OrderedDict.".  Well, technically yes, except there's no convenient way to instantiate an OrderedDict with more than one element at a time.

There's not *that* much difference between writing:

OrderedDict(a=1, b=2, c=3)  # doesn't work as expected

and

OrderedDict([('a', 1), ('b', 2), ('c', 3)])


that justifies creating OrderedDicts the hard way:

d = OrderedDict()
d['a'] = 1
d['b'] = 2
d['c'] = 3

as earlier suggested. Yes, it would be nice to use the first version, but it is a Nice To Have, not a Must Have.


> So now you're back to rewriting calling sites into order-preserving lists-of-tuples again.  Which is why I think the OrderedDict.__init__ case is in and of itself compelling.   ;-)

OrderedDicts are important, but they aren't important enough to impose their requirements on the entire language.

* I've already mentioned the risk of performance costs. Most applications of dicts do not care about order. Imposing performance costs on those applications in order to satisfy a few that do is probably a bad trade off, unless those costs are trivial.

* We're not just talking about CPython here. Anything that is part of the language must be applicable to all Python implementations, not just the big four (CPython, Jython, IronPython, PyPy) but all the little ones as well. Even if CPython adopts Raymond Hettinger's dict optimization that keeps order as a side-effect, do we really want to make that a language requirement?

(I'm not saying that we should, or shouldn't, but only that the stakes are bigger than just CPython.)

What's important is not just the magnitude of the changes necessary to make kwargs ordered, but the possible implementations that may be ruled out. It is possible for a language to over-specify features as well as under-specify, and we should be cautious about doing so.


[...]
> Or consider this small change to the rules for passing **kwargs. Currently, Python guarantees to build a new dict-like object out of anything you pass, then update it. What if Python instead guaranteed to build a new mapping of the same type (e.g., via copy.copy), then update it in order? Then you could just do this:
>
>      create_element('img', alt="Some cool stuff.", src="coolstuff.jpg", **OrderedDict())

I can't help but feel that if order of keyword arguments is important, you should take an ordered dict as an explicit argument rather than accept keyword arguments.

Given:

def create_element(tag, alt, src):
     pass


even if kwargs become ordered in some way, how will your create_element function distinguish between these two calls?

create_element('img', alt='something', src='something.jpg')
create_element('img', src='something.jpg', alt='something')

I don't believe it can. Hence, when order is important, you cannot use keyword arguments to provide arguments *even if kwargs are ordered*. But if you write your function like this:

def create_element(tag, mapping):
     pass

and call it like this:

create_element('img', OrderedDict([('alt', 'something'), ('src', 'something.jpg')]))

then you can get order for free. Yes, it's a little less convenient to use a list of tuples than nice keyword syntax, but that's a solution that doesn't impose any costs on code that doesn't care about ordering.



For what it's worth, I'm +0 on specifying that dicts must keep creation order unless items are deleted. I'm -1 on making OrderedDict the default dictionary type.



-- 
Steven


More information about the Python-ideas mailing list