Frage Null-Objekt in Python?


Wie verweise ich auf das Null-Objekt in Python?


804
2017-07-20 11:53


Ursprung


Antworten:


In Python ist das 'Null'-Objekt das Singleton None.

Der beste Weg, Dinge auf "Noneness" zu überprüfen, ist die Verwendung des Identity-Operators, is:

if foo is None:
    ...

1119
2017-07-20 11:54



Es heißt nicht null wie in anderen Sprachen, aber None. Es gibt immer nur eine Instanz dieses Objekts, so dass Sie die Übereinstimmung mit überprüfen können x is None (Identitätsvergleich) statt x == None, wenn du willst.


53
2017-07-20 11:56



Um in Python die Abwesenheit eines Wertes darzustellen, können Sie die Keiner Wert (types.NoneType.None) für Objekte und "" (oder len () == 0) für Strings. Deshalb:

if yourObject is None:  # if yourObject == None:
    ...

if yourString == "":  # if yourString.len() == 0:
    ...

In Bezug auf den Unterschied zwischen "==" und "ist" sollte das Testen auf Objektidentität mit "==" ausreichend sein. Da die Operation "is" jedoch als Objektidentitätsoperation definiert ist, ist es wahrscheinlich korrekter, sie zu verwenden als "==". Nicht sicher, ob es sogar einen Geschwindigkeitsunterschied gibt.

Wie auch immer, Sie können sehen:


26
2018-03-03 11:11



None, Pythons Null?

Da ist kein null in Python gibt es stattdessen None. Wie schon gesagt, ist der genaueste Weg zu testen, dass etwas gegeben wurde None als ein Wert ist die Verwendung der is Identity-Operator, der testet, dass sich zwei Variablen auf dasselbe Objekt beziehen.

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

Die Grundlagen

Es gibt und kann nur eins sein None

None ist die einzige Instanz der Klasse NoneType und alle weiteren Versuche, diese Klasse zu instanziieren, werden das gleiche Objekt zurückgeben, das macht None ein Singleton. Neuankömmlinge in Python sehen oft Fehlermeldungen, die erwähnt werden NoneType und frage mich, was es ist. Es ist meine persönliche Meinung, dass diese Nachrichten einfach nur erwähnen könnten None mit Namen, weil, wie wir in Kürze sehen werden, None lässt wenig Raum für Ambiguität. Also wenn du welche siehst TypeError Nachricht, die das erwähnt NoneType kann das nicht tun oder kann das nicht, nur wissen, dass es einfach der eine ist None das wurde auf eine Weise benutzt, die es nicht kann.

Ebenfalls, None ist eine eingebaute Konstante, sobald Sie Python starten, kann es von überall benutzt werden, egal ob in Modul, Klasse oder Funktion. NoneType Im Gegensatz dazu ist es nicht erforderlich, dass Sie zuerst einen Verweis darauf erhalten, indem Sie abfragen None für seine Klasse.

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

Du kannst nachschauen NoneEinzigartigkeit mit Pythons Identitätsfunktion id(). Es gibt die eindeutige Nummer zurück, die einem Objekt zugewiesen wurde, jedes Objekt hat eins. Wenn die ID von zwei Variablen gleich ist, dann zeigen 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 viel älteren Version von Python (vor 2.4) war es möglich, neu zuzuweisen None, aber 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 sicher anzunehmen, dass alle None Referenzen sind gleich. Es gibt keine "Gewohnheit" None.

Um zu prüfen None benutze die is Operator

Wenn Sie Code schreiben, könnten Sie versucht sein, nach etwas zu suchen Nichtigkeit so was:

if value==None:
    pass

Oder um auf solche Unwahrheit zu prüfen

if not value:
    pass

Sie müssen die Implikationen verstehen und warum es oft eine gute Idee ist, explizit zu sein.

Fall 1: Testen, ob ein Wert ist None

warum tu das?

value is None

eher, als

value==None

Der erste entspricht:

id(value)==id(None)

Während der Ausdruck value==None wird tatsächlich so angewendet

value.__eq__(None)

wenn der Wert wirklich ist None dann bekommst du, was du erwartet hast.

>>> nothing = function_that_does_nothing()
>>> nothing.__eq__(None)
True

In den meisten Fällen wird das Ergebnis dasselbe sein, aber die __eq__() Methode öffnet eine Tür, die keine Garantie für Genauigkeit, da es in einer Klasse außer Kraft gesetzt werden kann, um besonderes Verhalten zu bieten.

Betrachten Sie diese Klasse.

>>> class Empty(object):
...     def __eq__(self, other):
...         return not other

Also versuchst 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

Fall 2: Verwenden None als boolescher

Die folgenden zwei Tests

if value:
    # do something

if not value:
    # do something

werden tatsächlich als bewertet

if bool(value):
    # do something

if not bool(value):
    # do something

None ist ein "falsey", was bedeutet, dass wenn es in einen Booleschen Wert umgewandelt wird, es zurückkehrt False und wenn angewendet die not Betreiber wird es zurückkehren True. Beachten Sie jedoch, dass es sich nicht um eine einzigartige Eigenschaft handelt None. Zusätzlich zu False Die Eigenschaft wird von leeren Listen, Tupeln, Mengen, Dicts, Strings sowie 0 und allen Objekten aus Klassen, die das implementieren, gemeinsam genutzt __bool__() magische Methode, um zurückzukehren 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

Wenn Sie also auf folgende Weise nach Variablen suchen, sollten Sie sich bewusst sein, was Sie in den Test einbeziehen oder ausschließen:

def some_function(value=None):
    if not value:
        value = init_value()

In dem oben genannten, meintest du anrufen? init_value() wenn der Wert speziell auf eingestellt ist NoneOder meinst du, dass ein Wert auf gesetzt ist? 0oder die leere Zeichenfolge oder eine leere Liste sollte ebenfalls die Initialisierung auslösen. Wie gesagt, sei achtsam. Wie es in Python oft der Fall ist Explizit ist besser als implizit.

None in der Praxis

None verwendet als ein Signalwert

None hat einen besonderen Status in Python. Es ist ein bevorzugter Grundlinienwert, da viele Algorithmen ihn als außergewöhnlichen Wert behandeln. In solchen Szenarien kann es als ein Flag verwendet werden, um zu signalisieren, dass eine Bedingung eine spezielle Behandlung erfordert (z. B. die Einstellung eines Standardwerts).

Sie können zuweisen None zu den Schlüsselwortargumenten einer Funktion und dann explizit auf sie prüfen.

def my_function(value, param=None):
    if param is None:
        # do something outrageous!

Sie können es als Standard zurückgeben, wenn Sie versuchen, zu einem Objektattribut zu gelangen und es dann explizit zu testen, bevor Sie etwas Spezielles tun.

value = getattr(some_obj, 'some_attribute', None)
if value is None:
    # do something spectacular!

Standardmäßig ein Wörterbuch get() Methode kehrt zurück None wenn Sie versuchen, auf einen nicht vorhandenen Schlüssel zuzugreifen:

>>> some_dict = {}
>>> value = some_dict.get('foo')
>>> value is None
True

Wenn Sie versuchen sollten, darauf zuzugreifen, indem Sie die tiefgestellte Notation verwenden a KeyError würde erhoben werden

>>> value = some_dict['foo']
KeyError: 'foo'

Genauso, wenn Sie versuchen, ein nicht existierendes Objekt zu löschen

>>> value = some_dict.pop('foo')
KeyError: 'foo'

die Sie mit einem Standardwert unterdrücken können, der normalerweise auf festgelegt 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 Anwendungen von None gelten, wenn es nicht als gültiger Wert betrachtet wird, sondern eher als ein Signal, etwas Besonderes zu tun. Es gibt Situationen, in denen es manchmal wichtig ist zu wissen, wo None kam aus, denn obwohl es als Signal verwendet wird, könnte es auch Teil der Daten sein.

Wenn Sie ein Objekt mit seinem Attribut abfragen getattr(some_obj, 'attribute_name', None) zurückkommen None sagt Ihnen nicht, ob das Attribut, auf das Sie zugreifen wollten, auf gesetzt wurde None oder wenn es überhaupt nicht im Objekt vorhanden war. Gleiche Situation beim Zugriff auf einen Schlüssel aus einem Wörterbuch wie some_dict.get('some_key')Du weißt nicht, ob some_dict['some_key'] fehlt oder wenn es nur eingestellt ist None. Wenn Sie diese Informationen benötigen, besteht die übliche Vorgehensweise darin, direkt auf das Attribut oder den Schlüssel innerhalb von a zuzugreifen try/except bauen:

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 dict:

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 man mit Objekt- und Wörterbuchfällen umgeht, was ist mit Funktionen? Das Gleiche, aber wir verwenden das Doppelstern-Schlüsselwort-Argument für dieses Ende:

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 oben genannten Code übersät ist try/except Muster einfach zu unterscheiden zwischen None Flaggen und None Daten, dann verwenden Sie einfach einen anderen Testwert. Es gibt ein Muster, bei dem ein Wert, der außerhalb der Menge gültiger Werte liegt, als Teil der Daten in einer Datenstruktur eingefügt wird und dazu verwendet wird, spezielle Bedingungen (z. B. Grenzen, Status usw.) zu steuern und zu testen. Ein solcher Wert heißt a Wächter und es kann so benutzt werden None wird als Signal verwendet. Es ist trivial, in Python einen Sentinel zu erstellen.

undefined = object()

Das undefined Objekt oben ist einzigartig und macht nichts von allem, was für ein Programm von Interesse sein könnte, es ist somit ein ausgezeichneter Ersatz für None als eine Fahne. Einige Einschränkungen gelten, 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 dict

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 bereits erwähnt, haben benutzerdefinierte Wächter einige Vorbehalte. Erstens sind sie keine Keywords wie None, also schützt Python sie nicht. Du kannst deine überschreiben undefined oben zu jeder Zeit, überall im Modul ist es definiert, so sei vorsichtig, wie Sie sie aussetzen und verwenden. Als nächstes wird die Instanz von zurückgegeben object() ist kein Singleton, wenn Sie diesen Aufruf 10 Mal machen, erhalten Sie 10 verschiedene Objekte. Schließlich ist die Verwendung eines Sentinels sehr eigenwillig. Ein Sentinel ist spezifisch für die Bibliothek, in der es verwendet wird. 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.


26
2018-01-29 15:34



Pro Wahrheitswert-Test, 'None' testet direkt als FALSE, daher genügt der einfachste Ausdruck:

if not foo:

0
2017-09-24 23:15