Antworten:
Die Aussage
if A:
ruft auf A.__nonzero__()(siehe Dokumentation zu speziellen Methodennamen ) und verwendet den Rückgabewert dieser Funktion. Hier ist die Zusammenfassung:
object.__nonzero__(self)Wird aufgerufen, um Wahrheitswerttests und den eingebauten Betrieb zu implementieren
bool(). sollte zurückgebenFalseoder oderTrueoder ihre ganzzahligen Äquivalente0oder1. Wenn diese Methode nicht definiert ist,__len__()wird sie aufgerufen, wenn sie definiert ist, und das Objekt wird als wahr betrachtet, wenn sein Ergebnis ungleich Null ist. Wenn eine Klasse weder__len__()noch definiert__nonzero__(), werden alle ihre Instanzen als wahr betrachtet.
Andererseits,
if A is not None:
vergleicht nur die Referenz Amit None, um festzustellen, ob sie gleich ist oder nicht.
if object(): passbeträgt ~ 0,130 usec pro Schleife, während if object() is not None: pass~ 0,135 usec beträgt. Auf jeden Fall sollten Sie nicht die Leistung verwenden, um zwischen diesen beiden zu wählen, sondern die Unterschiede in ihrer Funktionsweise betrachten, da sie nicht gleichwertig sind .
if A is not Nonescheint langsamer zu sein, da es sich um einen Vergleich handelt und der eingebaute Singleton Noneals Zwischenschritt zum Vergleichen geladen werden muss A(siehe dis.dis()). Korrigieren Sie mich, wenn ich falsch if A:liege, aber effizienter zu sein scheint, sobald Sie wirklich den Wahrheitswert und nicht die NoneIdentität testen möchten.
python -m timeit -s"a=0" "if a: pass" "else: pass"ist schneller als, python -m timeit -s"a=0" "if a is None: pass" "else: pass"aber python -m timeit -s"a=1" "if a: pass" "else: pass"langsamer. Könnte plattformabhängig sein, sehen Sie, ob Sie die gleichen Ergebnisse erhalten
is NoneTest war in der Tat der langsamste für mich. In Pypy haben sie alle genau das gleiche gemessen :)
Wie in PEP8 geschrieben :
Vergleiche mit Singletons wie None sollten immer mit 'is' oder 'is not' durchgeführt werden, niemals mit den Gleichheitsoperatoren .
Außerdem passen sie des Schreibens „ wenn x“ , wenn Sie wirklich bedeuten „ wenn x nicht None“ - zum Beispiel , wenn , ob eine Variable oder ein Argument zu testen , dass standardmäßig keine auf einen anderen Wert gesetzt wurde. Der andere Wert hat möglicherweise einen Typ (z. B. einen Container), der in einem booleschen Kontext falsch sein kann!
None, sondern nur für eine Wahrheitsprüfung. In diesem Fall if A:scheint es effizienter zu sein (nehmen Sie a dis.dis(), es gibt die zusätzlichen Schritte zum Laden des eingebauten Noneund Vergleichens mit if A is not None:, während es jump_ifim anderen Fall nur a gibt ).
if x: #x is treated True except for all empty data types [],{},(),'',0 False, and None
so ist es nicht dasselbe wie
if x is not None # which works only on None
Viele Funktionen geben None zurück, wenn keine geeigneten Ergebnisse vorliegen. Beispielsweise gibt die .first()Methode einer SQLAlchemy-Abfrage None zurück, wenn das Ergebnis keine Zeilen enthält. Angenommen, Sie haben einen Wert ausgewählt, der möglicherweise 0 zurückgibt, und müssen wissen, ob er tatsächlich 0 ist oder ob die Abfrage überhaupt keine Ergebnisse erzielt hat.
Eine gebräuchliche Redewendung besteht darin, dem optionalen Argument einer Funktion oder Methode den Standardwert None zu geben und dann zu testen, ob dieser Wert None ist, um festzustellen, ob er angegeben wurde. Beispielsweise:
def spam(eggs=None):
if eggs is None:
eggs = retrievefromconfigfile()
Vergleiche das mit:
def spam(eggs=None):
if not eggs:
eggs = retrievefromconfigfile()
Was passiert in letzterem Fall, wenn Sie anrufen spam(0)oder spam([])? Die Funktion erkennt (fälschlicherweise), dass Sie keinen Wert für übergeben haben, eggsund berechnet einen Standardwert für Sie. Das ist wahrscheinlich nicht was du willst.
Oder stellen Sie sich eine Methode wie "Rückgabe der Liste der Transaktionen für ein bestimmtes Konto" vor. Wenn das Konto nicht vorhanden ist, wird möglicherweise None zurückgegeben. Dies unterscheidet sich von der Rückgabe einer leeren Liste (was bedeuten würde, dass "dieses Konto existiert, aber keine Transaktionen aufgezeichnet hat").
Zum Schluss zurück zum Datenbankmaterial. Es gibt einen großen Unterschied zwischen NULL und einer leeren Zeichenfolge. Eine leere Zeichenfolge sagt normalerweise "hier gibt es einen Wert, und dieser Wert ist überhaupt nichts". NULL sagt "Dieser Wert wurde nicht eingegeben."
In jedem dieser Fälle möchten Sie verwenden if A is None. Sie suchen nach einem bestimmten Wert - Keine - und nicht nur nach einem Wert, der zufällig in "Falsch" umgewandelt wird.
Sie machen sehr unterschiedliche Dinge .
Die unten überprüft , ob A hat nichts außer den Werten False, [], None, ''und 0. Es überprüft den Wert von A.
if A:
Im Folgenden wird überprüft, ob A ein anderes Objekt als None ist. Es überprüft und vergleicht die Referenz (Speicheradresse) von A und None.
if A is not None:
UPDATE: Weitere Erklärung
Oft scheinen die beiden dasselbe zu tun, so dass viele Leute sie austauschbar verwenden - das ist eine wirklich schlechte Idee. Der Grund, warum die beiden die gleichen Ergebnisse liefern, ist oft ein reiner Zufall aufgrund von Optimierungen des Interpreters / Compilers wie Internierung oder etwas anderem.
Unter Berücksichtigung dieser Optimierungen verwenden Ganzzahlen und Zeichenfolgen mit demselben Wert denselben Speicherplatz. Das erklärt wahrscheinlich, warum zwei separate Zeichenfolgen so wirken, als wären sie gleich.
> a = 'test'
> b = 'test'
> a is b
True
> a == b
True
Andere Dinge verhalten sich jedoch nicht gleich.
> a = []
> b = []
> a is b
False
> a == b
True
Die beiden Listen haben eindeutig ein eigenes Gedächtnis. Überraschenderweise verhalten sich Tupel wie Strings.
> a = ()
> b = ()
> a is b
True
> a == b
True
Dies liegt wahrscheinlich daran, dass sich Tupel garantiert nicht ändern. Daher ist es sinnvoll, denselben Speicher wiederzuverwenden.
Fazit: Sie können sich nicht auf Zufälle verlassen . Nur weil es wie eine Ente quakt, heißt das nicht, dass es eine Ente ist. Verwenden Sie isund ==je nachdem, was Sie wirklich überprüfen möchten. Diese Dinge können schwer zu debuggen sein, da sie sich iswie eine Prosa lesen, die wir oft nur überfliegen.
Noneist ein Singleton, es ist kein Implementierungsdetail (im Gegensatz zu int oder string interning). Ich bin mir nicht sicher, ob ich dem folge, was du meinst.
Nonesich das anders verhält als intoder straufgrund von Internierung. Mein Punkt ist das isund ==ich überprüfe verschiedene Dinge; überprüft zuerst eine Speicheradresse, die zweite überprüft den Inhalt von Speicheradressen.
if A: wird sich als falsch erweisen, wenn A 0, Falsch, leere Zeichenfolge, leere Liste oder Keine ist, was zu unerwünschten Ergebnissen führen kann.
Die meisten Anleitungen, die ich gesehen habe, empfehlen, dass Sie verwenden sollten
wenn eine:
es sei denn, Sie haben einen Grund, genauer zu sein.
Es gibt einige geringfügige Unterschiede. Es gibt andere Werte als None, die False zurückgeben, z. B. leere Listen oder 0. Überlegen Sie sich also, worauf Sie wirklich testen.
None ist ein spezieller Wert in Python, der normalerweise eine nicht initialisierte Variable bezeichnet. Um zu testen, ob A diesen bestimmten Wert nicht hat, verwenden Sie:
if A is not None
Falsey-Werte sind eine spezielle Klasse von Objekten in Python (z. B. false, []). Um zu testen, ob A falsch ist, verwenden Sie:
if not A
Daher sind die beiden Ausdrücke nicht gleich. Und Sie sollten sie besser nicht als Synonyme behandeln.
PS Keine ist auch falsch, daher impliziert der erste Ausdruck den zweiten. Aber der zweite behandelt neben None noch andere Falsey-Werte. Nun ... wenn Sie sicher sein können, dass Sie in None keine anderen Falsey-Werte als None haben können, können Sie den ersten Ausdruck durch den zweiten ersetzen.
Das hängt vom Kontext ab.
Ich verwende es, if A:wenn ich eine AArt Sammlung erwarte , und ich möchte den Block nur ausführen, wenn die Sammlung nicht leer ist. Auf diese Weise kann der Anrufer jede gut erzogene Sammlung übergeben, ob leer oder nicht, und sie das tun lassen, was ich erwarte. Es ermöglicht Noneund Falseunterdrückt auch die Ausführung des Blocks, was gelegentlich zum Aufrufen von Code geeignet ist.
OTOH, wenn ich erwarte , dass Aeinige völlig beliebiges Objekt sein , aber es Verzug geraten hätte zu None, dann habe ich immer verwenden if A is not None, als Code aufrufen absichtlich einen Verweis auf eine leere Sammlung, leeren String oder ein 0-wertigen numerischen Typ bestanden haben könnte, oder Boolescher Wert Falseoder eine Klasseninstanz, die im booleschen Kontext falsch ist.
Auf der anderen Seite, wenn ich erwarte A, dass es sich um eine spezifischere Sache handelt (z. B. eine Instanz einer Klasse, deren Methoden ich aufrufen werde), die jedoch Nonestandardmäßig verwendet werden könnte , und ich betrachte die standardmäßige boolesche Konvertierung als a Eigentum der Klasse Es macht mir nichts aus, alle Unterklassen durchzusetzen, dann erspare ich if A:meinen Fingern nur die schreckliche Last, zusätzliche 12 Zeichen einzugeben.
Ich habe eine Datei namens erstellt test.pyund sie auf dem Interpreter ausgeführt. Sie können ändern, was Sie möchten, um sicherzugehen, wie sich die Dinge hinter den Kulissen entwickeln.
import dis
def func1():
matchesIterator = None
if matchesIterator:
print( "On if." );
def func2():
matchesIterator = None
if matchesIterator is not None:
print( "On if." );
print( "\nFunction 1" );
dis.dis(func1)
print( "\nFunction 2" );
dis.dis(func2)
Dies ist der Assembler-Unterschied:

Quelle:
>>> import importlib
>>> reload( test )
Function 1
6 0 LOAD_CONST 0 (None)
3 STORE_FAST 0 (matchesIterator)
8 6 LOAD_FAST 0 (matchesIterator)
9 POP_JUMP_IF_FALSE 20
10 12 LOAD_CONST 1 ('On if.')
15 PRINT_ITEM
16 PRINT_NEWLINE
17 JUMP_FORWARD 0 (to 20)
>> 20 LOAD_CONST 0 (None)
23 RETURN_VALUE
Function 2
14 0 LOAD_CONST 0 (None)
3 STORE_FAST 0 (matchesIterator)
16 6 LOAD_FAST 0 (matchesIterator)
9 LOAD_CONST 0 (None)
12 COMPARE_OP 9 (is not)
15 POP_JUMP_IF_FALSE 26
18 18 LOAD_CONST 1 ('On if.')
21 PRINT_ITEM
22 PRINT_NEWLINE
23 JUMP_FORWARD 0 (to 26)
>> 26 LOAD_CONST 0 (None)
29 RETURN_VALUE
<module 'test' from 'test.py'>
Python> = 2,6,
wenn wir schreiben wie
if A:
generiert eine Warnung als,
FutureWarning: Das Verhalten dieser Methode wird sich in zukünftigen Versionen ändern. Verwenden Sie stattdessen einen bestimmten Test 'len (elem)' oder 'elem is not None'.
Also können wir verwenden
if A is not None:
A is not Noneist schneller, da es viel weniger Arbeit zu tun gibt