Antworten:
In Python ist das 'null'-Objekt der Singleton None
.
Der beste Weg, um Dinge auf "Noneness" zu überprüfen, ist die Verwendung des Identitätsoperators is
:
if foo is None:
...
None
, Python ist null?Es gibt kein null
in Python, stattdessen gibt es None
. Wie bereits erwähnt, besteht der genaueste Weg, um zu testen, ob etwas None
als Wert angegeben wurde, darin, den is
Identitätsoperator zu verwenden , der testet, dass zwei Variablen auf dasselbe Objekt verweisen.
>>> foo is None
True
>>> foo = 'bar'
>>> foo is None
False
None
None
ist die einzige Instanz der Klasse, NoneType
und alle weiteren Versuche, diese Klasse zu instanziieren, geben dasselbe Objekt zurück, wodurch None
ein Singleton erstellt wird. Python-Neulinge sehen häufig Fehlermeldungen, die erwähnen NoneType
und sich fragen, was es ist. Ich persönlich bin der Meinung, dass diese Nachrichten einfach nur namentlich erwähnt None
werden könnten, da sie, wie wir gleich sehen werden, None
wenig Raum für Unklarheiten lassen. Wenn Sie also eine TypeError
Nachricht sehen, in der erwähnt wird, dass NoneType
dies nicht oder nicht möglich ist, wissen Sie einfach, dass es einfach diejenige ist None
, die auf eine Weise verwendet wurde, die es nicht kann.
Ist auch None
eine eingebaute Konstante, sobald Sie Python starten, kann sie von überall verwendet werden, egal ob in Modul, Klasse oder Funktion. NoneType
Im Gegensatz dazu müssen Sie zuerst einen Verweis darauf erhalten, indem Sie None
nach seiner Klasse fragen .
>>> NoneType
NameError: name 'NoneType' is not defined
>>> type(None)
NoneType
Sie können die None
Eindeutigkeit mit der Identitätsfunktion von Python überprüfen id()
. Es gibt die einem Objekt zugewiesene eindeutige Nummer zurück, jedes Objekt hat eine. Wenn die ID zweier Variablen identisch ist, verweisen sie tatsächlich auf dasselbe Objekt.
>>> NoneType = type(None)
>>> id(None)
10748000
>>> my_none = NoneType()
>>> id(my_none)
10748000
>>> another_none = NoneType()
>>> id(another_none)
10748000
>>> def function_that_does_nothing(): pass
>>> return_value = function_that_does_nothing()
>>> id(return_value)
10748000
None
kann nicht überschrieben werdenIn einer viel älteren Version von Python (vor 2.4) war eine Neuzuweisung möglich None
, jedoch nicht mehr. Nicht einmal als Klassenattribut oder in den Grenzen einer Funktion.
# In Python 2.7
>>> class SomeClass(object):
... def my_fnc(self):
... self.None = 'foo'
SyntaxError: cannot assign to None
>>> def my_fnc():
None = 'foo'
SyntaxError: cannot assign to None
# In Python 3.5
>>> class SomeClass:
... def my_fnc(self):
... self.None = 'foo'
SyntaxError: invalid syntax
>>> def my_fnc():
None = 'foo'
SyntaxError: cannot assign to keyword
Es ist daher davon auszugehen, dass alle None
Referenzen gleich sind. Es gibt keinen "Brauch" None
.
None
Verwendung des is
BedienersWenn Sie Code schreiben, könnten Sie versucht sein, wie folgt auf Noneness zu testen :
if value==None:
pass
Oder um auf solche Unwahrheiten zu testen
if not value:
pass
Sie müssen die Auswirkungen verstehen und wissen, warum es oft eine gute Idee ist, explizit zu sein.
None
warum das tun
value is None
eher, als
value==None
Der erste entspricht:
id(value)==id(None)
Während der Ausdruck value==None
tatsächlich so angewendet wird
value.__eq__(None)
Wenn der Wert wirklich ist, erhalten None
Sie das, was Sie erwartet haben.
>>> nothing = function_that_does_nothing()
>>> nothing.__eq__(None)
True
In den meisten Fällen ist das Ergebnis dasselbe, aber die __eq__()
Methode öffnet eine Tür, die jegliche Garantie für die Genauigkeit ungültig macht, da sie in einer Klasse überschrieben werden kann, um ein spezielles Verhalten bereitzustellen.
Betrachten Sie diese Klasse.
>>> class Empty(object):
... def __eq__(self, other):
... return not other
Also probierst du es an None
und es funktioniert
>>> empty = Empty()
>>> empty==None
True
Aber dann funktioniert es auch mit der leeren Zeichenfolge
>>> empty==''
True
Und doch
>>> ''==None
False
>>> empty is None
False
None
als Boolescher WertDie folgenden zwei Tests
if value:
# do something
if not value:
# do something
werden in der Tat als bewertet
if bool(value):
# do something
if not bool(value):
# do something
None
ist ein "Falsey", was bedeutet, dass wenn er in einen Booleschen Wert umgewandelt wird, er zurückkehrt False
und wenn er angewendet wird, der not
Operator zurückkehrt True
. Beachten Sie jedoch, dass es sich nicht nur um eine Eigenschaft handelt None
. Zusätzlich zu sich False
selbst wird die Eigenschaft von leeren Listen, Tupeln, Mengen, Diktaten, Zeichenfolgen sowie 0 und allen Objekten aus Klassen, die die zurückzugebende __bool__()
magische Methode implementieren , gemeinsam genutzt False
.
>>> bool(None)
False
>>> not None
True
>>> bool([])
False
>>> not []
True
>>> class MyFalsey(object):
... def __bool__(self):
... return False
>>> f = MyFalsey()
>>> bool(f)
False
>>> not f
True
Achten Sie beim Testen auf Variablen auf folgende Weise besonders darauf, was Sie in den Test einschließen oder ausschließen:
def some_function(value=None):
if not value:
value = init_value()
Wollten Sie oben aufrufen, init_value()
wenn der Wert speziell auf eingestellt ist None
, oder meinten Sie, dass ein auf 0
oder die leere Zeichenfolge oder eine leere Liste festgelegter Wert auch die Initialisierung auslösen sollte. Wie ich schon sagte, sei achtsam. Wie so oft in Python ist explizit besser als implizit .
None
in der PraxisNone
als Signalwert verwendetNone
hat einen besonderen Status in Python. Es ist ein beliebter Basiswert, da viele Algorithmen ihn als außergewöhnlichen Wert behandeln. In solchen Szenarien kann es als Flag verwendet werden, um zu signalisieren, dass eine Bedingung eine spezielle Behandlung erfordert (z. B. das Festlegen eines Standardwerts).
Sie können None
den Schlüsselwortargumenten einer Funktion zuweisen und diese dann explizit testen.
def my_function(value, param=None):
if param is None:
# do something outrageous!
Sie können es als Standard zurückgeben, wenn Sie versuchen, das Attribut eines Objekts aufzurufen, und es dann explizit testen, bevor Sie etwas Besonderes tun.
value = getattr(some_obj, 'some_attribute', None)
if value is None:
# do something spectacular!
Standardmäßig wird die get()
Methode eines Wörterbuchs zurückgegeben , None
wenn versucht wird, auf einen nicht vorhandenen Schlüssel zuzugreifen:
>>> some_dict = {}
>>> value = some_dict.get('foo')
>>> value is None
True
Wenn Sie versuchen würden, mit der tiefgestellten Notation darauf zuzugreifen, wird a KeyError
ausgelöst
>>> value = some_dict['foo']
KeyError: 'foo'
Ebenso, wenn Sie versuchen, ein nicht vorhandenes Element zu platzieren
>>> value = some_dict.pop('foo')
KeyError: 'foo'
Dies können Sie mit einem Standardwert unterdrücken, der normalerweise auf eingestellt ist None
value = some_dict.pop('foo', None)
if value is None:
# booom!
None
wird sowohl als Flag als auch als gültiger Wert verwendetDie oben beschriebenen Verwendungen von None
gelten, wenn sie nicht als gültiger Wert angesehen werden, sondern eher als Signal, etwas Besonderes zu tun. Es gibt jedoch Situationen, in denen es manchmal wichtig ist zu wissen, woher sie None
stammen, da sie, obwohl sie als Signal verwendet werden, auch Teil der Daten sein können.
Wenn Sie ein Objekt für seine Attribut Abfrage mit getattr(some_obj, 'attribute_name', None)
zurückzubekommen None
Sie nicht sagen , ob das Attribut , das Sie zugreifen möchten , wurden eingestellt wurde None
oder ob es überhaupt von dem Objekt nicht gefunden . Dieselbe Situation beim Zugriff auf einen Schlüssel aus einem Wörterbuch wie some_dict.get('some_key')
: Sie wissen nicht, ob er some_dict['some_key']
fehlt oder nur auf gesetzt ist None
. Wenn Sie diese Informationen benötigen, versuchen Sie normalerweise, direkt aus einem try/except
Konstrukt heraus auf das Attribut oder den Schlüssel zuzugreifen :
try:
# equivalent to getattr() without specifying a default
# value = getattr(some_obj, 'some_attribute')
value = some_obj.some_attribute
# now you handle `None` the data here
if value is None:
# do something here because the attribute was set to None
except AttributeError:
# we're now hanling the exceptional situation from here.
# We could assign None as a default value if required.
value = None
# In addition, since we now know that some_obj doesn't have the
# attribute 'some_attribute' we could do something about that.
log_something(some_obj)
Ähnlich mit Diktat:
try:
value = some_dict['some_key']
if value is None:
# do something here because 'some_key' is set to None
except KeyError:
# set a default
value = None
# and do something because 'some_key' was missing
# from the dict.
log_something(some_dict)
Die obigen zwei Beispiele zeigen, wie mit Objekt- und Wörterbuchfällen umgegangen wird. Was ist mit Funktionen? Das Gleiche, aber wir verwenden zu diesem Zweck das Schlüsselwortargument mit doppelten Sternchen:
def my_function(**kwargs):
try:
value = kwargs['some_key']
if value is None:
# do something because 'some_key' is explicitly
# set to None
except KeyError:
# we assign the default
value = None
# and since it's not coming from the caller.
log_something('did not receive "some_key"')
None
wird nur als gültiger Wert verwendetWenn Sie feststellen, dass Ihr Code mit dem obigen try/except
Muster übersät ist , nur um zwischen None
Flags und None
Daten zu unterscheiden , verwenden Sie einfach einen anderen Testwert. Es gibt ein Muster, bei dem ein Wert, der außerhalb des Satzes gültiger Werte liegt, als Teil der Daten in eine Datenstruktur eingefügt wird und zum Steuern und Testen spezieller Bedingungen (z. B. Grenzen, Status usw.) verwendet wird. Ein solcher Wert wird als Sentinel bezeichnet und kann so verwendet werden None
, wie er als Signal verwendet wird. Es ist trivial, einen Sentinel in Python zu erstellen.
undefined = object()
Das undefined
obige Objekt ist einzigartig und macht nicht viel, was für ein Programm von Interesse sein könnte. Es ist daher ein hervorragender Ersatz für None
eine Flagge. Es gelten einige Einschränkungen, mehr dazu nach dem Code.
Mit Funktion
def my_function(value, param1=undefined, param2=undefined):
if param1 is undefined:
# we know nothing was passed to it, not even None
log_something('param1 was missing')
param1 = None
if param2 is undefined:
# we got nothing here either
log_something('param2 was missing')
param2 = None
Mit Diktat
value = some_dict.get('some_key', undefined)
if value is None:
log_something("'some_key' was set to None")
if value is undefined:
# we know that the dict didn't have 'some_key'
log_something("'some_key' was not set at all")
value = None
Mit einem Objekt
value = getattr(obj, 'some_attribute', undefined)
if value is None:
log_something("'obj.some_attribute' was set to None")
if value is undefined:
# we know that there's no obj.some_attribute
log_something("no 'some_attribute' set on obj")
value = None
Wie ich bereits erwähnt habe, sind benutzerdefinierte Sentinels mit einigen Einschränkungen verbunden. Erstens sind sie keine Schlüsselwörter wie None
, also schützt Python sie nicht. Sie können Ihre undefined
obigen Angaben jederzeit und an jeder Stelle im Modul überschreiben , an der sie definiert sind. Seien Sie also vorsichtig, wie Sie sie verfügbar machen und verwenden. Als nächstes ist die von zurückgegebene Instanz object()
kein Singleton. Wenn Sie diesen Aufruf 10 Mal ausführen, erhalten Sie 10 verschiedene Objekte. Schließlich ist die Verwendung eines Sentinels sehr eigenwillig. Ein Sentinel ist spezifisch für die Bibliothek, in der er verwendet wird, und daher sollte sein Umfang im Allgemeinen auf die Interna der Bibliothek beschränkt sein. Es sollte nicht "auslaufen". Externer Code sollte nur dann darauf aufmerksam werden, wenn der Zweck darin besteht, die API der Bibliothek zu erweitern oder zu ergänzen.
Es heißt nicht null wie in anderen Sprachen, aber None
. Es gibt immer nur eine Instanz dieses Objekts, sodass Sie die Äquivalenz mit x is None
(Identitätsvergleich) überprüfen können, anstatt x == None
, wenn Sie möchten.
None
. Dann werden all diese klugen Leute, die sich mit ihnen vergleichen NoneType
, triumphieren!
Um in Python das Fehlen eines Werts darzustellen, können Sie den Wert None ( types.NoneType.None ) für Objekte und "" (oder len () == 0 ) für Zeichenfolgen verwenden. Deshalb:
if yourObject is None: # if yourObject == None:
...
if yourString == "": # if yourString.len() == 0:
...
In Bezug auf den Unterschied zwischen "==" und "is" sollte das Testen der Objektidentität mit "==" ausreichend sein. Da die Operation "ist" jedoch als Objektidentitätsoperation definiert ist, ist es wahrscheinlich korrekter, sie zu verwenden, als "==". Ich bin mir nicht sicher, ob es überhaupt einen Geschwindigkeitsunterschied gibt.
Wie auch immer, Sie können einen Blick darauf werfen:
0 == false
kehrt true
ist , weil die Doppel-Gleichheitsoperator Art Zwang tut. Mit dem Triple-Equals-Operator wird jedoch 0 === false
zurückgegeben false
, da 'number' und 'boolean' unterschiedliche Typen sind.
true
in Bedingungen behandelt . In Rust and Go 0
und false
sind verschiedene Typen, die nicht für Gleichheit verglichen werden können.
Null ist ein spezieller Objekttyp wie:
>>>type(None)
<class 'NoneType'>
Sie können überprüfen, ob sich ein Objekt in der Klasse 'NoneType' befindet:
>>>variable = None
>>>variable is None
True
Weitere Informationen finden Sie unter Python Docs
Bei der Prüfung des Wahrheitswertes wird 'Keine' direkt als FALSCH getestet, sodass der einfachste Ausdruck ausreicht:
if not foo:
True
für jeden falschen Wert zurückgegeben, nicht nur None
.
egg is None
überegg == None
: Letzteres kann überlastet werden und ist wahrscheinlich zu brechen , wenn sie mit keinem gültigen Objekt zu vergleichen (hängt davon ab , wie es umgesetzt wird , aber erwarten Sie nicht alle Vergleiche mit nehmen Keiner Rechnung, nicht wahr?) , währendis
immer gleich funktioniert.