Frage Warum vergleicht das ** kwargs-Mapping mit einem anders geordneten OrderedDict?


Gemäß PEP 468:

Ab Version 3.6 behält Python die Reihenfolge der Schlüsselwortargumente bei, die an eine Funktion übergeben werden. Um dies zu erreichen, sammelte Kwargs wird jetzt ein geordnetes Mapping sein. Beachten Sie, dass dies nicht unbedingt bedeutet OrderedDict.

Warum verhindert dieses geordnete Mapping in diesem Fall den Gleichheitsvergleich mit Pythons kanonisch geordnetem Mappingtyp, dem 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

Obwohl die Iterationsreihenfolge jetzt beibehalten wird, kwargs scheint sich wie ein normales Diktat für die Vergleiche zu verhalten. Python hat ein C implementiertes geordnetes dict seit 3.5, so könnte es denkbar gewesen sein, direkt verwendet worden zu sein (oder, wenn die Leistung immer noch ein Problem war, eine schnellere Implementierung unter Verwendung einer dünnen Unterklasse des kompakten Diktats von 3.6).

Warum berücksichtigt die von einer Funktion empfangene geordnete Zuordnung nicht die Reihenfolge in Gleichheitsvergleichen?


11
2018-03-07 18:50


Ursprung


Antworten:


Die Antwort auf Ihr erstes "Warum" ist, dass diese Funktion durch Verwendung einer Ebene implementiert wird dict in CPython. Wie @ Ryans Antwort darauf hinweist, bedeutet dies, dass Vergleiche nicht auftragsabhängig sind.

Das zweite "warum" hier ist, warum dies kein verwendet OrderedDict.

Mit einem OrderedDict war der ursprüngliche Plan, wie in der erster Entwurf von PEP 486. Die Idee, wie iteriert in dieser Antwort, war es, einige Perf Daten zu sammeln, um den Effekt des Plug - in zu zeigen OrderedDict da dies ein Streitpunkt war, als die Idee vorher herum schwebte. Der Autor der PEP spielte sogar auf das Ordnungsbewahrungsdikt an, das eine andere Option in der endgültige Antwort auf diesem Thread.

Danach scheint die Konversation zu diesem Thema bis zum Erscheinen von Python 3.6 abgeklungen zu sein. Als das neue Diktat kam, hatte es den netten Nebeneffekt, einfach PEP 486 aus der Box zu implementieren (wie Diese Python-Dev-Thread-Zustände). Die spezifische Nachricht in diesem Thread gibt auch an, wie der Autor den Begriff wollte OrderedDict in Ordered Mapping geändert werden. (Dies ist auch wenn a neues Commit auf PEP 468, nach dem ersten, wurde gemacht)

Soweit ich das beurteilen kann, wurde diese Umformulierung vorgenommen, um es anderen Implementierungen zu ermöglichen, diese Funktion so zu gestalten, wie sie es für richtig halten. CPython und PyPy hatten bereits ein Diktat, das einfach PEP 468 implementierte, andere Implementierungen könnten sich für ein OrderedDict, andere könnten für eine andere Form einer geordneten Zuordnung gehen.

Das öffnet jedoch die Tür für ein Problem. Es bedeutet, dass theoretisch in einer Implementierung von Python 3.6 mit einem OrderedDict Als die Struktur, die diese Eigenschaft implementiert, wäre der Vergleich auftragsbezogen, während dies in anderen (CPython) nicht der Fall wäre. (In Python 3.7, alle dicts müssen einfüge-geordnet sein, so dass dieser Punkt wahrscheinlich unwichtig ist, da alle Implementierungen ihn verwenden würden **kwargs)

Obwohl es ein Problem scheint, ist es wirklich nicht. Wie @ user2357112 darauf hingewiesen hat, gibt es keine Garantie auf ==. PEP 468 nur garantiert Bestellung. Soweit ich sagen kann, == Im Grunde ist die Implementierung definiert.


Kurz gesagt, es ist vergleichbar in CPython weil kwargs In CPython ist ein dict und es ist ein dict weil nach 3.6 das Ganze hat einfach funktioniert.


6
2018-03-07 21:52



Egal was eine "geordnete Zuordnung" bedeutet, solange es nicht unbedingt ist OrderedDict, OrderedDictIst es == wird seine Bestellung nicht berücksichtigen. Dokumente:

Gleichheitsprüfungen zwischen OrderedDict Objekte sind auftragsabhängig und werden als implementiert list(od1.items())==list(od2.items()). Gleichheitsprüfungen zwischen OrderedDict Objekte und andere Mapping Objekte sind wie normale Wörterbücher nicht geordnet. Dies erlaubt OrderedDict Objekte, die überall ersetzt werden, wo ein normales Wörterbuch verwendet wird.


14
2018-03-07 18:52



"Ordered Mapping" bedeutet nur, dass das Mapping die Ordnung bewahren muss. Es bedeutet nicht, dass die Reihenfolge Teil des Mappings sein muss == Beziehung.

Der Zweck von PEP 468 besteht lediglich darin, die Bestellinformationen zu bewahren. Ordnung haben zu sein == würde eine Rückwärtsinkompatibilität ohne wirklichen Nutzen für einen der Anwendungsfälle, die PEP 468 motiviert haben, erzeugen OrderedDict wäre auch teurer (seit OrderedDict behält immer noch seine eigene separate verkettete Liste, um die Reihenfolge zu verfolgen, und sie kann diese verkettete Liste nicht verlassen, ohne große O-Effizienz in zu opfern popitem und move_to_end).


9
2018-03-07 19:08



Nur um hinzuzufügen, wenn Sie diese Überprüfung vornehmen möchten (ohne sich auf ein Implementierungsdetail zu verlassen (das selbst dann nicht in Python 3.7 enthalten sein wird), tun Sie es einfach

from collections import OrderedDict
>>> data = OrderedDict(zip('xy', 'xy'))
>>> def foo(**kwargs):
...     return OrderedDict(kwargs) == data

da dies garantiert wahr ist.


1
2018-03-07 18:57