with - title of graph python




Das Set-Literal ergibt ein anderes Ergebnis als der Set-Funktionsaufruf (2)

Es hängt alles von der Reihenfolge ab, in der das Set erstellt wird, kombiniert mit dem Fehler, den Sie bei Ihrer anderen Frage entdeckt haben . Es scheint, dass das Literal in der entgegengesetzten Reihenfolge zur Konvertierung aus einer Liste erstellt wird.

>>> {0, x, y}
set([0j, Decimal('0')])
>>> {y, x, 0}
set([0])

Warum löscht der set Funktionsaufruf die Dupes, das Parsen eines Set-Literal jedoch nicht?

>>> x = Decimal('0')
>>> y = complex(0,0)
>>> set([0, x, y])
{0}
>>> {0, x, y}
{Decimal('0'), 0j}

(Python 2.7.12. Möglicherweise dieselbe Ursache wie für this ähnliche Frage)


Setzt den Test auf Gleichheit, und bis es neue Python-Versionen gibt, kann die Reihenfolge, in der sie dies tun, abhängig von der Form, in der Sie die Werte an den zu erstellenden Satz übergeben, variieren, wie ich unten zeigen werde.

Da 0 == x wahr ist und 0 == y wahr ist, aber x == y falsch ist , ist das Verhalten hier wirklich undefiniert , da die Menge annimmt, dass x == y wahr sein muss, wenn auch die ersten beiden Tests wahr waren .

Wenn Sie die an set() Liste umkehren , erhalten Sie dieselbe Ausgabe wie mit einem Literal, da sich die Reihenfolge der Gleichheitstests ändert:

>>> set([y, x, 0])
set([0j, Decimal('0')])

und dasselbe für das Umkehren des Buchstabens:

>>> {y, x, 0}
set([0])

Was passiert, ist, dass das Mengenliteral die Werte in den Stapel lädt und dann die Stapelwerte in umgekehrter Reihenfolge zum neuen Mengenobjekt hinzugefügt werden.

Solange zuerst 0 geladen wird, werden die beiden anderen Objekte dann bereits im Set gegen 0 getestet. Sobald eines der beiden anderen Objekte zuerst geladen wird, schlägt der Gleichheitstest fehl und Sie erhalten zwei Objekte hinzugefügt:

>>> {y, 0, x}
set([Decimal('0'), 0j])
>>> {x, 0, y}
set([0j, Decimal('0')])

Das umgekehrte Hinzufügen von Elementen durch Setzen von Literalen ist ein Fehler, der in allen Versionen von Python vorhanden ist, die die Syntax bis Python 2.7.12 und 3.5.2 unterstützen. Es wurde kürzlich behoben, siehe Ausgabe 26020 (Teil von 2.7.13, 3.5.3 und 3.6, von denen noch keiner veröffentlicht wurde). Wenn Sie sich 2.7.12 ansehen, können Sie sehen, dass BUILD_SET in ceval.c den Stack von oben nach unten liest:

# oparg is the number of elements to take from the stack to add
for (; --oparg >= 0;) {
    w = POP();
    if (err == 0)
        err = PySet_Add(x, w);
    Py_DECREF(w);
}

Während der Bytecode Elemente in umgekehrter Reihenfolge zum Stapel hinzufügt ( 0 auf dem Stapel drücken):

>>> from dis import dis
>>> dis(compile('{0, x, y}', '', 'eval'))
  2           0 LOAD_CONST               1 (0)
              3 LOAD_GLOBAL              0 (x)
              6 LOAD_GLOBAL              1 (y)
              9 BUILD_SET                3
             12 RETURN_VALUE

Das Problem wird behoben, indem die Elemente in umgekehrter Reihenfolge vom Stapel gelesen werden. Die Python 2.7.13-Version verwendet PEEK() anstelle von POP() (und ein STACKADJ() , um die Elemente anschließend aus dem Stapel zu entfernen):

for (i = oparg; i > 0; i--) {
    w = PEEK(i);
    if (err == 0)
        err = PySet_Add(x, w);
    Py_DECREF(w);
}
STACKADJ(-oparg);

Das Problem der Gleichheitsprüfung hat dieselbe Ursache wie die andere Frage. Die Decimal() -Klasse weist hier einige Gleichheitsprobleme mit complex auf, die in Python 3.2 behoben wurden (indem Decimal() Vergleiche mit complex und einigen anderen numerischen Typen unterstützt, die zuvor nicht unterstützt wurden ).





python-internals