On Fri, Jan 21, 2011 at 2:42 AM, Guido van Rossum firstname.lastname@example.org wrote:
On Thu, Jan 20, 2011 at 6:05 AM, M.-A. Lemburg email@example.com wrote:
Nick Coghlan wrote:
Yeah, simply making the kwargs dict always ordered is likely the way we would do it. That's also the only solution with any chance of working by default with the way most decorators are structured (accepting *args and **kwargs and passing them to the wrapped function).
How often do you really need this ?
In which of those cases wouldn't a static code analysis give you the call order of the parameters already ?
"Nice to have" is not good enough to warrant a slow down of all function calls involving keyword arguments, adding overhead for other Python implementations and possibly causing problems with 3rd party extensions relying on getting a PyDict for the keyword arguments object.
What he says.
I actually agree as well, but I was misremembering how the construction of the kwargs dict worked and hence was thinking that was the only possible way this could work (since the interpreter didn't know anything about the target function while building the dict). Actually checking with dis.dis and looking at the associated code in ceval.c corrected my misapprehension (the function is actually retrieved first, while the kwargs are still on the stack in the appropriate order, so it is theoretically possible for the function to influence how the args are stored).
So, as an alternative proposal, perhaps it would be possible to add a new protocol that allowed a callable to flag that an ordered dictionary should be used for kwargs (e.g. an "__ordered_call__" boolean attribute, with C level flags to speed up the common builtin callable cases). A @functools.ordered_call decorator could then just do "__ordered_call__ = True" to set the flag appropriately. (You could also be even more flexible and devise a protocol that supported any type for kwargs, but I think that would just be far more complicated without a corresponding increase in expressive power)
Ordinary calls that used "x=y" or "**d" would be slowed down marginally due to the check for the new attribute on the supplied callable, but that impact should be minimal (especially for the builtin cases, which would just be checking a C struct field) and other calls would be entirely unaffected.
The CPython specific impact would largely be limited to update_keyword_args() and implementing C level fields with associated __ordered_call__ properties on the various builtin callable objects. There would also need to be a new variant of PyEval_EvalCodeEx that either used an ordered dictionary for kwdict, or else allowed kwdict to be created and passed in by the calling code rather than implicitly created via PyDict_New().
A builtin version of collections.OrderedDict would still be a precursor to this idea though, so creating a _collections.OrderedDict C implementation still sounds like the right starting point for anyone that is particularly keen to see this idea progress.