Nullobjekt in Python?

1193

Wie verweise ich auf das Null-Objekt in Python?

Eidechse
quelle

Antworten:

1629

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:
    ...
Ben James
quelle
125
Und der Grund für die Wahl egg is Noneüber egg == 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ährend isimmer gleich funktioniert.
94
Warum haben die Python-Designer nicht einfach "null" gewählt? Muss einfach anders sein, nicht wahr? ;)
Vidar
35
@Vidar 'None' ist kein Mangel an einem Objekt (wie 'null' eine Nullreferenz ist), es ist ein tatsächliches Objekt. Sie erhalten niemals ein 'None'-Objekt, das für ein Objekt übergeben wird, das von einem anderen Typ als' NoneType 'ist. Es ist auch kein Sprachkonzept. Es ist nicht in die Sprache Python integriert, sondern Teil der Standardbibliothek von Python. Keine! == (ahem) Null
Rushyo
11
@ naught101 Es würde keinen Zweck erfüllen; da es kein Konzept von Zeigern gibt. Wenn Sie die ctypes-Bibliothek verwenden, wird None als Synonym für die Adresse Null verwendet, es gibt jedoch noch kein Sprachkonzept für eine Nullreferenz. In Python haben Sie immer auf ein Objekt verwiesen, auch wenn dieses Objekt None ist. Ich vermute, dass dies die Sprache stark vereinfacht.
Rushyo
5
Tolle Präsentation, die den 'Milliarden-Dollar-Fehler' erklärt, der der Null-Ref ist: infoq.com/presentations/… . Andere Optionen anstelle von null sind Optionen oder Vielleicht (benutzerdefinierte) Typen.
Michael Trouw
134

None, Python ist null?

Es gibt kein nullin Python, stattdessen gibt es None. Wie bereits erwähnt, besteht der genaueste Weg, um zu testen, ob etwas Noneals Wert angegeben wurde, darin, den isIdentitätsoperator zu verwenden , der testet, dass zwei Variablen auf dasselbe Objekt verweisen.

>>> foo is None
True
>>> foo = 'bar' 
>>> foo is None
False

Die Grundlagen

Es gibt und kann nur einen geben None

Noneist die einzige Instanz der Klasse, NoneTypeund alle weiteren Versuche, diese Klasse zu instanziieren, geben dasselbe Objekt zurück, wodurch Noneein Singleton erstellt wird. Python-Neulinge sehen häufig Fehlermeldungen, die erwähnen NoneTypeund sich fragen, was es ist. Ich persönlich bin der Meinung, dass diese Nachrichten einfach nur namentlich erwähnt Nonewerden könnten, da sie, wie wir gleich sehen werden, Nonewenig Raum für Unklarheiten lassen. Wenn Sie also eine TypeErrorNachricht sehen, in der erwähnt wird, dass NoneTypedies 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 Noneeine eingebaute Konstante, sobald Sie Python starten, kann sie von überall verwendet werden, egal ob in Modul, Klasse oder Funktion. NoneTypeIm Gegensatz dazu müssen Sie zuerst einen Verweis darauf erhalten, indem Sie Nonenach seiner Klasse fragen .

>>> NoneType
NameError: name 'NoneType' is not defined
>>> type(None)
NoneType

Sie können die NoneEindeutigkeit 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 werden

In 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 NoneReferenzen gleich sind. Es gibt keinen "Brauch" None.

Zum Testen auf NoneVerwendung des isBedieners

Wenn 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.

Fall 1: Testen, ob ein Wert ist None

warum das tun

value is None

eher, als

value==None

Der erste entspricht:

id(value)==id(None)

Während der Ausdruck value==Nonetatsächlich so angewendet wird

value.__eq__(None)

Wenn der Wert wirklich ist, erhalten NoneSie 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 Noneund 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

Fall 2: Verwendung Noneals Boolescher Wert

Die 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

Noneist ein "Falsey", was bedeutet, dass wenn er in einen Booleschen Wert umgewandelt wird, er zurückkehrt Falseund wenn er angewendet wird, der notOperator zurückkehrt True. Beachten Sie jedoch, dass es sich nicht nur um eine Eigenschaft handelt None. Zusätzlich zu sich Falseselbst 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 0oder 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 Praxis

None als Signalwert verwendet

Nonehat 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 Noneden 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 , Nonewenn 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 KeyErrorausgelö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 verwendet

Die oben beschriebenen Verwendungen von Nonegelten, 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 Nonestammen, 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 NoneSie nicht sagen , ob das Attribut , das Sie zugreifen möchten , wurden eingestellt wurde Noneoder 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/exceptKonstrukt 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 verwendet

Wenn Sie feststellen, dass Ihr Code mit dem obigen try/exceptMuster übersät ist , nur um zwischen NoneFlags und NoneDaten 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 undefinedobige 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 Noneeine 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 undefinedobigen 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.

Michael Ekoka
quelle
Was ist mit: Keine == Sache?
hkBst
@hkBst Ich vermute, Ihre Frage bezieht sich darauf, wie Python die Gleichheit bewertet. Werfen
Michael Ekoka
Ah, also IIUC, das normalerweise immer noch etwas anruft .__ eq__? In diesem Fall ziehe ich meinen Vorschlag zurück.
hkBst
@MichaelEkoka können Sie die Quelle für diese beeindruckenden und nützlichen Informationen teilen.
Anidhya Bhatnagar
Standardverfahren. Einige Hinweise dazu finden Sie im Python-Tutorial , aber das Lesen des Quellcodes beliebter Projekte ist mein Ratschlag Nummer eins, um schnell in das idiomatische Python einzutauchen .
Michael Ekoka
67

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.

AndiDog
quelle
25
Ich werde einen Weg finden, Python durch erneutes Instanziieren zu brechen None. Dann werden all diese klugen Leute, die sich mit ihnen vergleichen NoneType, triumphieren!
Zenexer
28

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:

Paolo Rovelli
quelle
8
Soweit ich weiß, gibt (0 == false) in JEDER Programmiersprache true zurück. Dies liegt daran, dass false als 0 und "true" als alles codiert ist, was NICHT 0 ist. Bitte beachten Sie jedoch nicht, dass der Operator "is" nicht mit dem Operator "==" identisch ist. Dies ist mehr oder weniger der gleiche Unterschied zwischen "==" und "gleich" in Java. Der Operator "is" prüft tatsächlich, ob ZWEI OBJEKTE gleich sind (dieselbe Instanz und NICHT derselbe Inhalt)!
Paolo Rovelli
12
Paolo, FYI, (0 == false) gibt nicht in jeder Programmiersprache true zurück. Ein schnelles Gegenbeispiel wäre Scala, wobei (0 == false) false zurückgibt, und ich bin sicher, dass Scala nicht die einzige Programmiersprache ist, die beim Vergleich einer Zahl mit einem Booleschen Wert false zurückgibt.
Rob Wilton
2
OK habe es! Dann sagen wir in den meisten Programmiersprachen.
Paolo Rovelli
3
In JavaScript ist der Grund , 0 == falsekehrt trueist , weil die Doppel-Gleichheitsoperator Art Zwang tut. Mit dem Triple-Equals-Operator wird jedoch 0 === falsezurückgegeben false, da 'number' und 'boolean' unterschiedliche Typen sind.
Jkdev
1
@PaoloRovelli in Lua, Ruby und Clojure wird 0 wie truein Bedingungen behandelt . In Rust and Go 0und false sind verschiedene Typen, die nicht für Gleichheit verglichen werden können.
Roller-baumeln
0

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


quelle
-1

Bei der Prüfung des Wahrheitswertes wird 'Keine' direkt als FALSCH getestet, sodass der einfachste Ausdruck ausreicht:

if not foo:
artejera
quelle
3
Nein, das wird es nicht. Dieser Ausdruck wird Truefür jeden falschen Wert zurückgegeben, nicht nur None.
insert_name_here
Richtig, und das einfache "wenn nicht foo:" würde die ursprüngliche Frage, wie angegeben, nicht richtig beantworten. Python ist jedoch dynamisch typisiert und lädt dazu ein, Syntaxprotokolle zu reduzieren. Daher erscheint es mir gültig, einfachere, ähnliche Konstrukte in Betracht zu ziehen.
Artejera