2017-02-16 4 views
0

Ich habe die folgende Merge-Code. Wenn die Zeile if ib is len(b) or ... so geändert wird, dass sie doppelt gleich ==: if ib == len(b) or ... verwendet, löst der Code keine IndexError Ausnahme aus.Python 3 Index ist len ​​(l) bedingte Auswertung Fehler

Dies ist sehr unerwartet, weil:

  • len (b) auf eine Zahl ausgewertet wird und is entspricht == für ganze Zahlen. Sie können es testen: ein Python-Ausdruck

    (1 is len([0])) 
    

    ausgewertet True zu sein.

  • Die Eingabe für die Funktion ist range(1500, -1, -1), und Bereichsobjekte werden in python3 anders behandelt. Ich vermutete, dass, da die Eingabe als Bereichsinstanz behandelt wurde, die Längenauswertung möglicherweise eine Instanz anstelle eines ganzzahligen Primitivs war. Dies ist wieder seltsam weil

    1 is len(range(1)) 
    

    Sie auch True als Ergebnis gibt.

Ist das ein Fehler bei der bedingten Auswertung in Python3?

Tom Caswell geliefert diese folgenden Nutzungs ausdrücklich in unserer Diskussion, ich bin Kopie einfügen es hier für Ihre Nachricht:

tt = [j is int(str(j)) for j in range(15000)] 

nur die ersten 256 Artikel sind True. Der Rest sind False hahahaha.


Das ursprüngliche Skript:

def merge_sort(arr): 
    if len(arr) >= 2: 
     s = int(len(arr)/2) 
     a = merge_sort(arr[:s]) 
     b = merge_sort(arr[s:]) 
     ia = 0 
     ib = 0 
     new_arr = [] 
     while len(new_arr) < len(arr): 
      try: 
       if ib is len(b) or a[ia] <= b[ib]: 
        new_arr.append(a[ia]) 
        ia += 1 
       else: 
        new_arr.append(b[ib]) 
        ib += 1 
      except IndexError: 
       print(len(a), len(b), ia, ib) 
       raise IndexError 
     return new_arr 
    else: 
     return arr 

print(merge_sort(range(1500, -1, -1))) 
+0

Kein Fehler, 'ist' Testobjekt Identität,' == 'testet Wert Gleichheit.Wenn Sie '==' in Ihrem Bedingungsausdruck verwenden, ist dieser kurzgeschlossen, so dass er niemals versucht, 'b [ib]' zu indexieren, also kein IndexError. – AChampion

+0

@AChampion Danke für den Kommentar! Ich glaube, dass beide Versionen kurzgeschlossen sind. "ist" sollte für Integer-Primitive gleich sein. Dies ist ein Fehler für 'ist'. – episodeyang

+2

Ihr Test um '1 == len ([0])' vs '1 ist len ​​([0])' ist fehlerhaft, weil Python Ganzzahlen mit bestimmten niedrigen Werten zwischenspeichert (siehe https://docs.python.org/3/ c-api/long.html # c.PyLong_FromLong). Ich glaube nicht, dass Sie einen Python-Fehler gefunden haben - er scheint sich wie dokumentiert zu verhalten. –

Antwort

3

Python garantiert nicht, dass zwei Ganzzahl-Instanzen mit gleichem Wert die gleiche Instanz sind. Im folgenden Beispiel liegt der Grund für die Gleichheit der ersten 256 Vergleiche darin, dass Python -5 in 256 in Long zwischenspeichert. Dieses Verhalten ist hier beschrieben: https://docs.python.org/3/c-api/long.html#c.PyLong_FromLong

Beispiel:

tt = [j is int(str(j)) for j in range(500)] 
plt.plot(tt) 

enter image description here

IIRC, die jeder von ihnen passieren die is Test eine Implementierung spezifische Optimierung Detail.

+0

Danke Tom! Mit Alex 'Link zum Python-Caching von 'Long' ist diese Antwort perfekt. https://docs.python.org/3/c-api/long.html#c.PyLong_FromLong – episodeyang

1

is prüft, ob zwei Argumente beziehen sich auf das gleiche Objekt , == prüft, ob zwei Argumente denselben Wert haben. Sie können nicht davon ausgehen, dass sie dasselbe bedeuten, sie haben unterschiedliche Verwendungszwecke und Sie erhalten eine Fehlermeldung, wenn Sie versuchen, sie synonym zu verwenden.

+0

es ist wahr, und ich bin mir bewusst, aber ich denke, der Grund hier ist subtiler als dies. Ich glaube, das hat etwas damit zu tun, wie das 'Bereich'-Objekt behandelt wurde, und es ist ein Fehler mit Python. – episodeyang

+1

Danke für die Antwort! Ich akzeptierte die andere Antwort aufgrund des darin enthaltenen Testfalls und editierte sie mit einem Link zur Python-Dokumentation. – episodeyang