¿Por qué la vista de las claves de OrderedDict compara insensible a los pedidos?

¿Por qué la vista de las claves de OrderedDict compara insensible a los pedidos?

 >>> from collections import OrderedDict >>> xy = OrderedDict([('x', None), ('y', None)]) >>> yx = OrderedDict([('y', None), ('x', None)]) >>> xy == yx False >>> xy.keys() == yx.keys() True 

La vista de las claves de OrderedDict debería comportarse como un OrderedSet, pero en su lugar se comporta igual que dict.keys (es decir, como un set habitual).

Mismo “problema” en python2:

 >>> xy.viewkeys() == yx.viewkeys() True 

Son tipos diferentes, ( odict_keys es una subclase de dict_keys )

 >>> type(xy.keys()) odict_keys >>> type({}.keys()) dict_keys 

Y ya hay disponible una comparación de claves sensibles al orden que podrían haber sido usadas de manera trivial, pero aparentemente solo se usa como una comprobación posterior para la comparación rica y odiosa.

¿Es esta una decisión de diseño, o un error? Si es una decisión de diseño, ¿dónde podría encontrar una discusión de la justificación?

Parece que OrderedDict delega la implementación de los diversos objetos de vista a la implementación común de dict ; este sigue siendo el caso incluso en Python 3.5, donde OrderedDict obtuvo una implementación acelerada de C ( delega la construcción del objeto a _PyDictView_New y no proporciona ninguna anulación para la función de comparación enriquecida de la vista genérica).

Básicamente, OrderedDict vistas de OrderedDict con la misma orden en que OrderedDict haría con su respaldo de OrderedDict (porque no hay costo para hacerlo), pero para operaciones similares a un set , actúan como un set , utilizando igualdad de contenido, controles de subconjuntos / superconjuntos, etc.

Esto hace que la opción de ignorar el pedido tenga sentido hasta cierto punto; para algunas operaciones de set (p. ej & , & , | , ^ ), el valor de retorno es un set sin orden (porque no hay un OrderedSet , e incluso si existiera, qué orden se usa para algo como & donde la ordenación puede ser diferente en ¿Cada vista?), obtendría comportamientos inconsistentes si algunas de las operaciones de tipo set fueran sensibles al orden y otras no. Y sería aún más extraño cuando dos vistas de claves de OrderedDict fueran sensibles a la orden, pero la comparación de OrderedDict vistas de OrderedDict vistas de OrderedDict no lo era.

Como señalé en los comentarios, puede obtener una comparación de keys sensibles al pedido con bastante facilidad con:

 from operator import eq # Verify that keys are the same length and same set of values first for speed # The `all` check then verifies that the known identical keys appear in the # same order. xy.keys() == yx.keys() and all(map(eq, xy, yx)) # If you expect equality to occur more often than not, you can save a little # work in the "are equal" case in exchange for costing a little time in the # "not even equal ignoring order case" by only checking length, not keys equality: len(xy) == len(yz) and all(map(eq, xy, yx)) 

No puedo encontrar nada publicado, pero creo que esta lógica podría justificar el comportamiento:

Si tiene dos diccionarios, d1 y d2, esperaría que al comparar las claves se verifique si tienen las mismas claves, ¿no?

 def compare_dict_keys(d1, d2): d1.keys() == d2.keys() 

Esta función debe comportarse de la misma manera para cualquier tipo de diccionario (y OrderedDict es un tipo de dict ). Parecería incorrecto si tal función comenzara a devolver False solo porque d1 y d2 están ordenados.

En otras palabras, todos deberían evaluar lo mismo (y lo hacen):

 >>> {1:2, 3:4}.keys() == {3:4, 1:2}.keys() True >>> {1:2, 3:4}.keys() == OrderedDict([(3,4),(1,2)]).keys() True >>> OrderedDict([(1,2),(3,4)]).keys() == OrderedDict([(3,4),(1,2)]).keys() True 

Pero OrderedDict es especial, ¿no es así?

Lo que OrderedDict le ofrece es la garantía de orden cuando realiza una iteración. La misma garantía existe para OrderedDict.keys() , pero sin romper la compatibilidad con dict .