Why does the ** kwargs match against another ordered OrderedDict?
According to PEP 468 :
Since version 3.6 Python will preserve the order of the keyword arguments passed to the function. For this, the collected kwargs will now be sorted display . Note that this does not necessarily mean
OrderedDict
.
In this case, why is it ordered comparison does not account for the comparison of equality with the canonical ordered Python type display collections.OrderedDict
:
>>> from collections import OrderedDict
>>> data = OrderedDict(zip('xy', 'xy'))
>>> def foo(**kwargs):
... return kwargs == data
...
>>> foo(x='x', y='y') # expected result: True
True
>>> foo(y='y', x='x') # expected result: False
True
Although the iteration order is now preserved, kwargs
it seems to behave just like a normal dict for comparisons. Python has a C implemented ordered dict since 3.5 , so it could possibly have been used directly (or if performance is still a concern, a faster implementation using a thin subclass 3.6 compact dict).
Why is the ordered collation obtained by the function not ordered when comparing comparisons?
source to share
The answer to your first "why" is that this feature is implemented using a simple dict
CPython. As @Ryan points out, this means comparisons will not be order sensitive.
Second "why" that's why it doesn't use OrderedDict
...
Using OrderedDict
was the initial blueprint as stated in the first draft of PEP 486. The idea, as an iteration of this answer , was to collect some primary data to show the effect of connecting to
OrderedDict
as it was a controversial point where the idea was posted around earlier. The author of the PEP even referred to the order retaining the dict being another option in the final answer in this thread.
After that, the conversation on the topic seemed to have died away until Python 3.6 came along. When the new dictar came out, it had a nice side effect of implementing PEP 486 out of the box (as is the state of the Python-dev thread ). The specific post in this thread also indicates how the author wanted the termOrderedDict
was changed to ordered collation. (This is also when a new commit was made on PEP 468 , after the original)
As far as I can tell, this entry was made so that other implementations can provide this functionality as they see fit. CPython and PyPy already had a dict that easily implemented PEP 468, other implementations might chooseOrderedDict
, others might go for another form of ordered display. However, this opens the door to a problem. This means that in theory, when implementing Python 3.6 with
OrderedDict
as a structure that implements this function the comparison will be order sensitive, while others (CPython) will not. (In Python 3.7, everything
dict
must be ordered in order, so this point is likely to be controversial since all implementations will use it for
**kwargs
)
While this sounds like a problem, it really isn't. As @ user2357112 pointed out, ==
there is no guarantee. PEP 468 only guarantees ordering. As far as I can tell, ==
is largely implementation-defined.
In short, it compares the value in CPython, because kwargs
in CPython it is dict
, and a dict
, because after 3.6
that it just worked.
source to share
Whatever "ordered collation" means, if not necessary OrderedDict
, OrderedDict
s ==
ignore its order. Documents:
Equality tests between objects are
OrderedDict
order sensitive and are implemented aslist(od1.items())==list(od2.items())
. Equality tests between objectsOrderedDict
and other objectsMapping
are order-independent like regular dictionaries. This allows objects to be replacedOrderedDict
wherever a regular dictionary is used.
source to share
"Ordered mapping" means that the display must preserve order. This does not mean that the order should be part of the display relationship ==
.
The purpose of PEP 468 is to preserve order information. Ordering to be a part ==
would result in lagging incompatibilities with no real benefit for any of the use cases that motivated PEP 468. The use would OrderedDict
also be more costly (as OrderedDict
it still keeps its own separate linked list to keep track of and can't give up on it) linked list without sacrificing much O's efficiency in popitem
and move_to_end
).
source to share
Just add if you want to do this check (without relying on an implementation detail (which even then won't be in python 3.7)), just do
from collections import OrderedDict
>>> data = OrderedDict(zip('xy', 'xy'))
>>> def foo(**kwargs):
... return OrderedDict(kwargs) == data
since this is guaranteed to be True.
source to share