>
> The only way to make eggs end up as order-preserving is to change Python so that all functions (or at least all functions defined inside other functions) are order-preserving.
>
> Either you or someone else suggested that if Python could just pass the kwargs dict straight through instead of unpacking and repacking it, that would help. But it wouldn't.
Agreed. (Pretty sure that wasn't me. :) ) That would be a non-option for other reasons anyway.
[more snipped]
> Or consider your original example (with explicit a and b params on spam before **kwargs) with memoize, where the kwargs in eggs has a, b, c, and d, but the one inside spam has only c and d.
That should be a non-issue given how the data is packed into a new kwargs.
>
> Now, obviously you could fix any particular wrapper. Presumably your magic decorator works by doing something detectable from Python, like a new co_flags flag. So, we could define two new functions (presumably in inspect and functools, respectively):
>
>
> def preserves_kwargs_order(func):
> return func.__code__.co_flags & 16
>
> def wrap_preserve_kwargs_order(func):
> def wrapper(inner):
> if inspect.preserves_kwargs_order(func):
> return preserve_kwargs_order(inner)
> else:
> return inner
> return wrapper
>
> And now, all you have to do is add one line to most decorators and they're once again perfect forwarders:
>
> def memoize(func):
>
> _cache = {}
> @functools.wrap_preserve_kwargs_order(func)
> def wrapper(*args, **kwargs):
> if (args, kwargs) not in _cache:
> _cache[args, kwargs] = func(*args, **kwargs)
> return _cache[args, kwargs]
> return wrapper
>
>
> But the point is, you still have to add that decorator to every wrapper function in the world or they're no longer perfect forwarders.
Nice.
>
> You could even add that wrap_preserve_kwargs_order call into functools.wraps, and that would fix _many_ decorators (because many decorators are written to use functools.wraps), but still not all.
Also nice.