Según PEP 468 :
A partir de la versión 3.6, Python conservará el orden de los argumentos de palabras clave que se pasan a una función. Para lograr esto, los kwargs recopilados ahora serán un mapeo ordenado . Tenga en cuenta que esto no significa necesariamente
OrderedDict
.
En ese caso, ¿por qué este mapeo ordenado no respeta la comparación de igualdad con el tipo de mapeo ordenado canónico de Python, las 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
Aunque ahora se conserva el orden de iteración, parece que kwargs
se comportan como un dict normal para las comparaciones. Python tiene un dictado ordenado implementado en C desde 3.5 , por lo que es posible que se haya usado directamente (o, si el rendimiento aún fuera una preocupación, una implementación más rápida usando una subclase delgada del dictado compacto 3.6).
¿Por qué el mapeo ordenado que recibe una función no respeta el orden en las comparaciones de igualdad?
Independientemente de lo que signifique una "asignación ordenada", siempre que no sea necesariamente OrderedDict
, OrderedDict
's ==
no tendrá en cuenta su orden. Documentos:
Las pruebas de igualdad entre los objetos
OrderedDict
son sensibles al orden y se implementan comolist(od1.items())==list(od2.items())
. Las pruebas de igualdad entre los objetosOrderedDict
y otros objetosMapping
son insensibles al orden como los diccionarios normales. Esto permite que los objetosOrderedDict
se sustituyan en cualquier lugar donde se use un diccionario normal.
"Asignación ordenada" solo significa que la asignación debe conservar el orden. No significa que el orden tenga que ser parte de la relación ==
del mapeo.
El propósito de PEP 468 es solo preservar la información de pedido. Hacer que el orden sea parte de ==
produciría incompatibilidad con versiones anteriores sin ningún beneficio real para ninguno de los casos de uso que motivaron PEP 468. Usar OrderedDict
también sería más costoso (ya que OrderedDict
aún mantiene su propia lista vinculada separada para rastrear el orden, y puede No abandone esa lista enlazada sin sacrificar la eficiencia de gran O en popitem
y move_to_end
).
La respuesta a su primer 'por qué' es porque esta característica se implementa mediante el uso de un dict
simple en CPython. Como señala la respuesta de @Ryan, esto significa que las comparaciones no serán sensibles al orden.
El segundo 'por qué' aquí es por qué esto no usa un OrderedDict
.
Usar un OrderedDict
fue el plan inicial como se indica en el primer borrador de PEP 486. La idea, como se indica en esta respuesta , era recopilar algunos datos de rendimiento para mostrar el efecto de conectar el OrderedDict
ya que este era un punto de discusión cuando el La idea se planteó antes. El autor del PEP incluso aludió a que el dictamen de preservación del orden era otra opción en la respuesta final de ese hilo.
Después de eso, la conversación sobre el tema parece haberse calmado hasta que apareció Python 3.6. Cuando llegó el nuevo dict, tuvo el agradable efecto secundario de simplemente implementar PEP 486 de forma inmediata (como afirma este hilo de Python-dev ). El mensaje específico en ese hilo también establece cómo el autor quería que el término OrderedDict
se cambiara a Asignación ordenada. (Esto también es cuando se realizó una nueva confirmación en PEP 468 , después de la inicial)
Por lo que puedo decir, esta nueva redacción se realizó para permitir que otras implementaciones proporcionen esta característica como mejor les parezca. CPython y PyPy ya tenían un dict que implementaba fácilmente PEP 468, otras implementaciones podrían optar por un OrderedDict
, otras podrían optar por otra forma de mapeo ordenado.
Sin embargo, eso abre la puerta a un problema. Significa que, teóricamente, en una implementación de Python 3.6 con un OrderedDict
como estructura que implementa esta característica, la comparación sería sensible al orden mientras que en otros (CPython) no lo sería. (En Python 3.7, se requiere que todos los dict
estén ordenados por inserción, por lo que este punto probablemente sea discutible ya que todas las implementaciones lo usarían para **kwargs
)
Aunque parece un problema, en realidad no lo es. Como señaló @ user2357112, no hay garantía en ==
. PEP 468 solo garantiza el pedido. Por lo que puedo decir, ==
está básicamente definido por la implementación.
En resumen, se compara igual en CPython porque kwargs
en CPython es un dict
y es un dict
porque después de 3.6
todo funcionó.