resueltos recorrer ordereddict lista elementos ejercicios diccionarios diccionario dentro agregar python python-3.x dictionary ordereddictionary

recorrer - ordereddict python



¿Por qué los valores de un OrderedDict no son iguales? (3)

Con Python 3:

>>> from collections import OrderedDict >>> d1 = OrderedDict([(''foo'', ''bar'')]) >>> d2 = OrderedDict([(''foo'', ''bar'')])

Quería verificar la igualdad:

>>> d1 == d2 True >>> d1.keys() == d2.keys() True

Pero:

>>> d1.values() == d2.values() False

¿Sabes por qué los valores no son iguales?

He probado esto con Python 3.4 y 3.5.

Después de esta pregunta, publiqué en la lista de correo de Python-Ideas para obtener detalles adicionales:

https://mail.python.org/pipermail/python-ideas/2015-December/037472.html


Desafortunadamente, las dos respuestas actuales no abordan el motivo de esto, sino que se centran en cómo se hace esto. Esa discusión en la lista de correo fue increíble, así que resumiré las cosas:

Para odict.keys / dict.keys y odict.items / dict.items :

  • odict.keys ( subclase de dict.keys ) admite la comparación debido a su conformidad con collections.abc.Set (es un objeto similar a un conjunto). Esto es posible debido al hecho de que las keys dentro de un diccionario (ordenadas o no) tienen la garantía de ser únicas y halables.
  • odict.items ( subclase de dict.items ) también admite la comparación por el mismo motivo que .keys . itemsview está permitido hacer esto ya que genera el error apropiado si uno de los item (específicamente, el segundo elemento que representa el valor) no es hashable, sin embargo se garantiza la unicidad (debido a que las keys son únicas):

    >>> od = OrderedDict({''a'': []}) >>> set() & od.items() TypeErrorTraceback (most recent call last) <ipython-input-41-a5ec053d0eda> in <module>() ----> 1 set() & od.items() TypeError: unhashable type: ''list''

    Para ambas keys vista, items , la comparación usa una función simple llamada all_contained_in (bastante legible) que usa el método de objetos __contain__ para verificar la membresía de los elementos en las vistas involucradas.

Ahora, sobre odict.values / dict.values :

  • Como se ha notado, odict.values ( subclase de dict.values [shocker]) no se compara como un objeto similar a un conjunto. Esto se debe a que los values de una valuesview de values no se pueden representar como un conjunto, las razones son dos:

    1. Lo más importante es que la vista puede contener duplicados que no se pueden descartar.
    2. La vista puede contener objetos no procesables (que, por sí solo, no son suficientes para no tratar la vista como un conjunto).

Como se indica en un comentario de user2357112 y de @abarnett en la lista de correo, odict.values / dict.values es un conjunto múltiple, una generalización de conjuntos que permite varias instancias de sus elementos. Intentar compararlos no es tan trivial como comparar keys o items debido a la duplicación inherente, el orden y el hecho de que probablemente deba tener en cuenta las claves que corresponden a esos valores. Deberían dict_values que se ven así:

>>> {1:1, 2:1, 3:2}.values() dict_values([1, 1, 2]) >>> {1:1, 2:1, 10:2}.values() dict_values([1, 1, 2])

en realidad ser igual a pesar de que los valores que corresponden a las teclas no son lo mismo? ¿Tal vez? ¿Tal vez no? No es directo de ninguna manera y conducirá a una confusión inevitable.

Sin embargo, lo importante es que no es trivial compararlos como lo está con las keys y los items , para resumir, con otro comentario de @abarnett en la lista de correo :

Si está pensando que podríamos definir qué deberían hacer los multisectos, a pesar de no tener un tipo de conjunto múltiple estándar o un ABC para ellos, y aplicar eso a las vistas de valores, la siguiente pregunta es cómo hacer eso en un tiempo mejor que cuadrático para los no fiables valores. (Y tampoco puede suponer que se ordene aquí.) ¿Sería una mejora tener una vista de valores durante 30 segundos y luego regresar con la respuesta que intuitivamente quería en lugar de dar la respuesta incorrecta en 20 milisegundos? (De cualquier forma, vas a aprender la misma lección: no compares las vistas de valores. Prefiero aprender eso en 20 milisegundos).


En Python 3, dict.keys() y dict.values() devuelven clases iterables especiales, respectivamente a collections.abc.KeysView y collections.abc.ValuesView . El primero hereda su método __eq__ del set , el segundo usa el object.__eq__ predeterminado object.__eq__ que prueba la identidad del objeto.


En python3, d1.values() y d2.values() son objetos collections.abc.ValuesView :

>>> d1.values() ValuesView(OrderedDict([(''foo'', ''bar'')]))

No los compare como un objeto, cámbielos a listas y luego compárelos:

>>> list(d1.values()) == list(d2.values()) True

Investigando por qué funciona para comparar claves, en _collections_abc.py de CPython, KeysView hereda de Set mientras ValuesView no:

class KeysView(MappingView, Set): class ValuesView(MappingView):

  • Seguimiento de __eq__ en ValuesView y sus padres:

    MappingView ==> Sized ==> ABCMeta ==> type ==> object .

    __eq__ se implementa solo en el object y no se reemplaza.

  • Por otro lado, KeysView hereda __eq__ directamente de Set .