Wie vergleicht Python 2.7 Elemente in einer Liste?

7

Ich bin heute auf dieses interessante Beispiel gestoßen.

%Vor% %Vor%

So scheint es, dass Vergleiche in Containern in Python anders funktionieren. Ich würde erwarten, dass der Aufruf von == die Implementierung jedes Objekts von __eq__ verwenden würde, sonst was ist der Punkt? Zusätzlich

%Vor% %Vor%

Bedeutet dies, dass Python is stattdessen in Container-Implementierungen von __eq__ verwendet? Gibt es einen Weg dazu?

Mein Anwendungsfall ist, dass ich eine Datenstruktur erstelle, die von einigen der collections ABCs erbt, und ich möchte Tests schreiben, um sicherzustellen, dass sich meine Struktur korrekt verhält. Ich dachte mir, es wäre einfach, einen Wert zu injizieren, der beim Vergleichen aufgezeichnet wurde, aber zu meiner Überraschung schlug der Test fehl, als ich sicherstellte, dass der Vergleich stattfand.

EDIT: Ich sollte erwähnen, dass dies auf Python 2.7 ist, aber ich sehe das gleiche Verhalten auf 3.3.

    
bheklilr 23.03.2015, 16:29
quelle

4 Antworten

13

Die zugrunde liegende CPython-Implementierung überspringt die Gleichheitsprüfung ( == ) für Elemente in einer Liste, wenn Elemente identisch sind ( is ).

CPython verwendet dies als eine Optimierung unter der Annahme, dass Identität Gleichheit bedeutet.

Dies ist in PyObject_RichCompareBool dokumentiert, das zum Vergleichen von Elementen verwendet wird:

  

Hinweis: Wenn o1 und o2 dasselbe Objekt sind, gibt PyObject_RichCompareBool () immer 1 für Py_EQ und 0 für Py_NE zurück.

Aus der Implementierung listobject.c :

%Vor%

Wie Sie sehen können, solange RichCompareBool ist 1 ( True ) werden die Elemente nicht überprüft.

Und von der object.c Implementierung von PyObject_RichCompareBool :

%Vor%

Um dies zu umgehen, müssen Sie die Elemente manuell vergleichen.

    
Reut Sharabani 23.03.2015, 16:42
quelle
10

Python testet die Gleichheit von Sequenzen wie folgt:

%Vor%

Sie können sehen, dass die Gleichheit der Elemente an jeder Position getestet wird nur , wenn die zwei Sequenzen die gleiche Länge haben, aber die Elemente an jeder Position nicht identisch sind. Wenn Sie die Verwendung von Gleichheitsprüfungen erzwingen möchten, benötigen Sie z. B.:

%Vor%     
jonrsharpe 23.03.2015 17:06
quelle
4

Wenn x is y , gibt es keinen Grund, x == y aufzurufen, nach Vertrag von == . Python nimmt diese Abkürzung.

Dies kann verifiziert / widerlegt werden, indem in den Tests ein eq1 und ein eq2 erstellt und anschließend [eq1] == [eq2] verwendet wird.

Hier ist ein Beispiel :

%Vor%

Wenn die Elemente is sind, ist kein == beteiligt.

Der Unterschied zu den Wörterbüchern kann ähnlich erklärt werden.

    
user2864740 23.03.2015 16:43
quelle
3

Beim Vergleich zweier Listen schließt die cPython-Implementierung Mitgliedervergleiche mithilfe der Objektgleichheit ( obj1 is obj2 ) kurz, da nach ein Kommentar im Code :

%Vor%

Wenn die zwei Objekte nicht genau das gleiche Objekt sind, dann führt cPython einen reichen Vergleich durch, indem% code_% verwendet wird, falls implementiert.

    
William Jackson 23.03.2015 17:07
quelle

Tags und Links