Python None-Vergleich: Soll ich “is” oder == verwenden?

Lesezeit: 8 Minuten

Benutzer-Avatar
Lehm Wardell

Mein Redakteur warnt mich, wenn ich vergleiche my_var == Noneaber keine Warnung, wenn ich benutze my_var is None.

Ich habe einen Test in der Python-Shell durchgeführt und festgestellt, dass beide eine gültige Syntax sind, aber mein Editor scheint das zu sagen my_var is None Ist bevorzugt.

Ist dies der Fall und wenn ja, warum?

  • PEP 8 sagt irgendwo, dass Sie mit Singletons vergleichen sollten ispython.org/dev/peps/pep-0008/#programming-recommendations

    – Volatilität

    9. Januar 2013 um 22:11 Uhr

  • Dieses Poster spricht von Python 3, und meine Frage betrifft Python 2.x. Ich bin mir nicht sicher, ob dies ein ausreichend großer Unterschied ist, um beides zu rechtfertigen, aber ich habe die Frage so bearbeitet, dass sie dies nur für den Fall enthält.

    – Lehm Wardell

    9. Januar 2013 um 22:30 Uhr

  • Ich glaube nicht, dass diese Frage wirklich ein Duplikat ist. Bei dem anderen ging es um == vs im Allgemeinen, bei diesem um None im Besonderen.

    – IJ Kennedy

    4. Mai 2014 um 21:47 Uhr

Benutzer-Avatar
mgilson

Zusammenfassung:

Verwenden is wenn Sie gegen ein Objekt prüfen möchten Identität (z. B. prüfen, ob var ist None). Verwenden == wenn Sie überprüfen möchten Gleichberechtigung (z. B. Is var gleicht 3?).

Erläuterung:

Sie können benutzerdefinierte Klassen haben, wo my_var == None wird zurückkehren True

z.B:

class Negator(object):
    def __eq__(self,other):
        return not other

thing = Negator()
print thing == None    #True
print thing is None    #False

is prüft auf Objekt Identität. Es gibt nur 1 Objekt Nonealso wenn du es tust my_var is Noneüberprüfen Sie, ob es sich tatsächlich um dasselbe Objekt handelt (nicht nur gleichwertig Objekte)

Mit anderen Worten, == ist eine Prüfung auf Äquivalenz (die von Objekt zu Objekt definiert ist), während is prüft auf Objektidentität:

lst = [1,2,3]
lst == lst[:]  # This is True since the lists are "equivalent"
lst is lst[:]  # This is False since they're actually different objects

  • Wann tut is None unterscheiden sich von == None?

    – Mixer

    9. Januar 2013 um 22:09 Uhr


  • @Blender In dem genannten Fall. __eq__ kann beliebig definiert werden, aber das Verhalten von is lässt sich nicht so einfach ändern.

    – Lev Levitsky

    9. Januar 2013 um 22:10 Uhr

  • @LevLevitsky: Eine der beispielhaften Verwendungen von Mython war „die Erweiterung der Protokolle, sodass sogar jeder Operator überlastet werden kann is“. Nach einem Kommentar zu den Listen änderte er das in „…sogar is (aber nur wenn du wahnsinnig bist).”

    – Abart

    9. Januar 2013 um 22:19 Uhr


  • +1, aber es wäre noch besser, wenn diese Antwort die PEP 8-Referenz enthalten würde, die die anderen tun (und erklärt, warum die Entscheidung hinter PEP 8 sinnvoll ist, was sie bereits tut).

    – Abart

    9. Januar 2013 um 22:20 Uhr


  • @abarnert – Mir war nicht einmal bewusst, dass PEP 8 hier eine Empfehlung ausgesprochen hat. Der Punkt ist, dass es sich um unterschiedliche Operatoren handelt, die unterschiedliche Dinge tun. Es mag Fälle geben, wo object == None eigentlich ist die richtige Redewendung (obwohl mir auf Anhieb keine einfällt). Man muss nur wissen, was man tut.

    – Mgilson

    9. Januar 2013 um 22:24 Uhr

Benutzer-Avatar
Benutzer4815162342

is wird im Allgemeinen bevorzugt, wenn beliebige Objekte mit Singletons verglichen werden None weil es schneller und vorhersehbarer ist. is vergleicht immer nach Objektidentität, wohingegen what == tun wird, hängt vom genauen Typ der Operanden und sogar von ihrer Reihenfolge ab.

Diese Empfehlung wird unterstützt von PEP 8die ausdrücklich erklärt dass “Vergleiche mit Singletons wie None immer gemacht werden sollten is oder is notniemals die Gleichheitsoperatoren.”

  • Danke, dass du das gepostet hast; Die akzeptierte Antwort macht einige interessante Punkte, aber Ihre Antwort auf die Frage ist viel direkter.

    – Lukas Davis

    26. April 2017 um 19:09 Uhr


  • Es scheint seltsam, sich auf etwas zu verlassen, das im Wesentlichen ein Implementierungsdetail ist. Warum sollte es mich interessieren, wie viele Instanzen von NoneType es gibt?

    – BallpointBen

    17. Januar 2019 um 18:44 Uhr

  • @BallpointBen Weil es so ist nicht ein Implementierungsdetail – es gibt nur eines None Objekt unter der globalen Konstante None. Wenn überhaupt, die NoneType ist ein Implementierungsdetail, weil die None Singleton muss haben etwas Typ. (Die Tatsache, dass Sie keine Instanzen dieses Typs erstellen können, ist ein guter Hinweis darauf, dass seine eine Instanz ein Singleton sein soll.)

    – Benutzer4815162342

    17. Januar 2019 um 18:48 Uhr

  • @BallpointBen Ich denke, der entscheidende Punkt ist, dass Python ein starkes Konzept der Objektidentität besitzt. Wenn Sie prüfen möchten, ob ein Objekt vergleichbar ist gleich zu Noneauf jeden Fall verwenden obj == None. Wenn Sie überprüfen möchten, ob ein Objekt ist Noneverwenden obj is None. Der Punkt der PEP 8-Empfehlung (und dieser Antwort) ist, dass die meisten Leute letzteres wollen, wenn sie nach None suchen wollen, und es ist auch schneller und klarer.

    – Benutzer4815162342

    22. Januar 2019 um 13:24 Uhr

  • None ist auch anders als zwischengespeicherte Objekte wie 0 und andere kleine Ganzzahlen, bei denen das Caching wirklich ein Implementierungsdetail ist. Der Unterschied besteht darin, dass eine ganze Zahl einen inneren Wert hat, der ihre Eigenschaften angibt, und sie kann berechnet werden. Auf der anderen Seite, None hat überhaupt keinen Zustand, es ist nur sein Identität das zählt und macht es besonders.

    – Benutzer4815162342

    22. Januar 2019 um 13:26 Uhr

Benutzer-Avatar
Thorsten Kranz

PEP 8 definiert, dass es besser ist, die zu verwenden is -Operator beim Vergleich von Singletons.

  • Ich sehe nirgendwo, wo PEP8 diese Empfehlung rechtfertigt. Hast du einen Link?

    – BT

    8. Juli um 21:25 Uhr

Benutzer-Avatar
Danferno

Ich habe kürzlich festgestellt, wo dies schief gehen kann.

import numpy as np
nparray = np.arange(4)

# Works
def foo_is(x=None):
    if x is not None:
        print(x[1])

foo_is()
foo_is(nparray)

# Code below raises 
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
def foo_eq(x=None):
    if x != None:
        print(x[1])

foo_eq()
foo_eq(nparray)

Ich habe eine Funktion erstellt, die optional ein numpy-Array als Argument akzeptiert und sich ändert, wenn es enthalten ist. Wenn ich mit Ungleichheitsoperatoren auf seine Einbeziehung teste !=, löst dies einen ValueError aus (siehe obigen Code). Wenn ich benutze is not noneder Code funktioniert korrekt.

Ein weiterer Fall, in dem sich “==” von “ist” unterscheidet. Wenn Sie Informationen aus einer Datenbank ziehen und prüfen, ob ein Wert vorhanden ist, ist das Ergebnis entweder ein Wert oder None.

Sehen Sie sich das if und else unten an. Nur „is“ funktioniert, wenn die Datenbank „None“ zurückgibt. Wenn Sie stattdessen == eingeben, funktioniert die if-Anweisung nicht, sie geht direkt zu else, obwohl das Ergebnis “None” ist. Hoffentlich drücke ich mich verständlich aus.

conn = sqlite3.connect('test.db')
c = conn.cursor()
row = itemID_box.get()

# pull data to be logged so that the deletion is recorded
query = "SELECT itemID, item, description FROM items WHERE itemID LIKE '%" + row + "%'"
c.execute(query)
result = c.fetchone()

if result is None:
    # log the deletion in the app.log file
    logging = logger('Error')
    logging.info(f'The deletion of {row} failed.')
    messagebox.showwarning("Warning", "The record number is invalid")
else:
    # execute the deletion
    c.execute("DELETE from items WHERE itemID = " + row)
    itemID_box.delete(0, tk.END)
    messagebox.showinfo("Warning", "The record has been deleted")
    conn.commit()
    conn.close()

Benutzer-Avatar
Doppelfelix

Ein nützlicher Leckerbissen zum Verständnis der Leute.

Der Grund, nach dem wir suchen Identität mit None liegt daran, dass Python immer nur den Wert speichert None an einem Ort im Gedächtnis, und jedes Objekt, das gleich ist None hat seinen Wert an derselben Stelle gespeichert. Es gibt eine Handvoll “besonderer Werte”, die diese Behandlung erhalten, und None ist nur einer von ihnen.

Aber die meisten Werte bekommen diese Sonderbehandlung nicht! Beispielsweise kann der Float 1,25 an verschiedenen Stellen im Speicher abgelegt werden:

a = None
b = None
a is b

WAHR

a = 1.25
b = 1.25
a is b

FALSCH

Es passiert einfach so None gehört zu den wenigen Werten, die immer an einer Stelle im Speicher gespeichert sind. Ein weiteres Beispiel ist eine beliebige ganze Zahl zwischen -5 und 256… da diese Ganzzahlen häufig verwendet werden, werden sie immer im Speicher gespeichert, und jede Ganzzahl mit diesem Wert wird an derselben Stelle im Speicher Ihres Computers gespeichert! Versuch es:

a = 256
b = 256
a is b

WAHR

a = 257
b = 257
a is b

FALSCH

Kann man sich also denken None als Teil einer speziellen Klasse von Werten, die immer eine konstante Speicheradresse haben. Deshalb können wir verwenden is um zu prüfen, ob zwei Variablen beides sind None… es wird nur geprüft, ob die Speicheradresse gleich ist.

Nehmen wir zum Beispiel die Liste. Schau hier:

a = list('Hello')
b = a
c = a[:]

Alle haben den gleichen Wert:

['H', 'e', 'l', 'l', 'o']
['H', 'e', 'l', 'l', 'o']
['H', 'e', 'l', 'l', 'o']

is bezieht sich auf den eigentlichen Speicherplatz, ob es sich um das konkrete Objekt von Interesse handelt:

print(a is b)
print(a is c)

Jetzt erhalten wir das gewünschte Ergebnis.

True
False

PEP 8 erwähnt dies auch und sagt: “Vergleiche mit Singletons wie None sollten immer mit is oder is not durchgeführt werden, niemals mit den Gleichheitsoperatoren.”

is ist auch schneller.

  • Ich denke, das PEP8-Zitat ist die richtige Antwort, vielleicht lohnt es sich, genau das zu präsentieren. Ich verstehe den Sinn deines Beispiels nicht.

    – Bob Hy

    18. Mai 2021 um 20:19 Uhr


  • Der Fragesteller sagte “wenn ja und warum”, also hier ist warum, um Fehler zu vermeiden. PEP8 ist eine Nebensache und ein Formatierungsleitfaden. Aber ich habe es trotzdem geschrieben, damit andere darauf verweisen können.

    – Aarav Dave

    19. Mai 2021 um 16:44 Uhr

  • Aber dein Beispiel ist falsch. Der Ausdruck print( None is print()) zeigt True (auf meiner Kopie von Python 3.8.6). Ich würde sagen, die Antwort auf die Frage „wenn ja, warum“ ist einfach, dass PEP8 diese Redewendung empfiehlt und der Herausgeber des Fragestellers diese Empfehlung durchsetzt.

    – Bob Hy

    20. Mai 2021 um 20:41 Uhr

  • Ach ja, tut mir leid. Es wäre None is print. Ich werde das gleich beheben.

    – Aarav Dave

    22. Mai 2021 um 0:55 Uhr

  • @AaravDave Ich werde dich nicht ablehnen, aber deine Korrektur ist auch falsch. None is print() gibt einen wahren Wert, weil print gibt nichts zurück. Sie prüfen also, ob die Rückgabe von print() ist Nonewas es ist. None is print gibt einen falschen Wert, weil Sie jetzt prüfen, ob die Funktion print ist der None Objekt. Diese Dinge haben nichts miteinander zu tun.

    – giusti

    8. April um 21:04 Uhr


1069000cookie-checkPython None-Vergleich: Soll ich “is” oder == verwenden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy