it-swarm.com.de

Null-Objekt in Python?

Wie verweise ich in Python auf das Null-Objekt?

1046
Lizard

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:
    ...
1412
Ben James

None, Pythons null?

Es gibt kein null in Python, stattdessen gibt es None. Wie bereits erwähnt, besteht der genaueste Weg, um zu testen, ob etwas als Wert None angegeben wurde, darin, den Identitätsoperator is zu verwenden, mit dem geprüft wird, ob 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

None ist die einzige Instanz der Klasse NoneType, und alle weiteren Versuche, diese Klasse zu instanziieren, geben dasselbe Objekt zurück, wodurch None zu einem Singleton wird. Neulinge in Python sehen häufig Fehlermeldungen, die NoneType erwähnen, und fragen sich, was das ist. Ich persönlich bin der Meinung, dass in diesen Nachrichten nur None beim Namen genannt werden kann, da None, wie wir gleich sehen werden, nur wenig Raum für Mehrdeutigkeiten lässt. Wenn Sie also eine TypeError Meldung sehen, in der erwähnt wird, dass NoneType dies nicht kann oder nicht kann, wissen Sie einfach, dass es einfach das ist, was None in gewisser Weise verwendet wurde das kann es nicht.

Außerdem ist None eine eingebaute Konstante. Sobald Sie Python starten, kann sie von überall verwendet werden, egal ob in Modulen, Klassen oder Funktionen. NoneType dagegen nicht, Sie müssen zuerst einen Verweis darauf abrufen, indem Sie None nach seiner Klasse fragen.

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

Sie können die Eindeutigkeit von None mit Pythons Identitätsfunktion id() überprüfen. Es gibt die eindeutige Nummer zurück, die einem Objekt zugewiesen wurde. 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 es möglich, None neu zuzuweisen, aber nicht mehr. Nicht einmal als Klassenattribut oder innerhalb 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

Man kann daher davon ausgehen, dass alle None Referenzen gleich sind. Es gibt kein "benutzerdefiniertes" None.

Verwenden Sie zum Testen auf None den Operator is

Wenn Sie Code schreiben, könnten Sie versucht sein, auf Noneness wie folgt zu testen:

if value==None:
    pass

Oder um auf solche Unwahrheiten zu testen

if not value:
    pass

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

Fall 1: Testen, ob ein Wert None ist

warum tust du das?

value is None

eher, als

value==None

Das erste ist äquivalent zu:

id(value)==id(None)

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

value.__eq__(None)

wenn der Wert wirklich None ist, erhalten 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 Methode __eq__() öffnet eine Tür, die jegliche Genauigkeitsgarantie 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

Sie probieren es also mit None aus und es funktioniert

>>> empty = Empty()
>>> empty==None
True

Dann funktioniert es aber auch mit der leeren Zeichenkette

>>> empty==''
True

Und doch

>>> ''==None
False
>>> empty is None
False

Fall 2: Verwenden von None als 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

None ist eine "Falsey", dh, wenn sie in einen Booleschen Wert umgewandelt wird, wird False zurückgegeben, und wenn der Operator not angewendet wird, wird True zurückgegeben. Beachten Sie jedoch, dass es sich nicht um eine Eigenschaft handelt, die nur für None gilt. Zusätzlich zu False selbst wird die Eigenschaft von leeren Listen, Tupeln, Mengen, Dikten, Zeichenfolgen sowie von 0 und allen Objekten aus Klassen gemeinsam genutzt, die die magische Methode __bool__() implementieren, um 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 von 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 init_value() aufrufen, wenn der Wert speziell auf None festgelegt ist, oder wollten Sie einen Wert auf 0 festlegen, oder die leere Zeichenfolge oder eine leere Zeichenfolge list sollte auch die Initialisierung auslösen. Wie ich schon sagte, sei achtsam. Wie so oft in Python explizit ist besser als implizit.

None in der Praxis

None wird als Signalwert verwendet

None hat in Python einen besonderen Status. Dies ist ein bevorzugter Basiswert, da er von vielen Algorithmen als außergewöhnlicher Wert behandelt wird. 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 den Schlüsselwortargumenten einer Funktion None zuweisen und dann explizit darauf testen.

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

Sie können es als Standardwert zurückgeben, wenn Sie versuchen, an das Attribut eines Objekts zu gelangen und es dann explizit zu testen, bevor Sie etwas Besonderes tun.

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

Standardmäßig gibt die get() -Methode eines Wörterbuchs None zurück, wenn versucht wird, auf einen nicht vorhandenen Schlüssel zuzugreifen:

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

Wenn Sie versuchen, mit der tiefgestellten Notation darauf zuzugreifen, wird KeyError ausgelöst

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

Ebenso, wenn Sie versuchen, ein nicht vorhandenes Element zu öffnen

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

dies können Sie mit einem Standardwert unterdrücken, der normalerweise auf None gesetzt ist.

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 None gelten, wenn es sich nicht um einen gültigen Wert handelt, sondern eher um ein Signal, etwas Besonderes zu tun. Es gibt jedoch Situationen, in denen es manchmal wichtig ist zu wissen, woher None stammt, da es auch Teil der Daten sein kann, obwohl es als Signal verwendet wird.

Wenn Sie ein Objekt nach seinem Attribut abfragen, während getattr(some_obj, 'attribute_name', None) zurückruft None, werden Sie nicht darüber informiert, ob das Attribut, auf das Sie zugreifen wollten, auf None gesetzt war oder ob es in der nicht vorhanden war Objekt. Dieselbe Situation, wenn Sie über ein Wörterbuch wie some_dict.get('some_key') auf einen Schlüssel zugreifen, wissen Sie nicht, ob some_dict['some_key'] fehlt oder nur auf None eingestellt ist. Wenn Sie diese Informationen benötigen, besteht die übliche Vorgehensweise darin, 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 verhält es sich 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 beiden obigen Beispiele zeigen, wie mit Objekt- und Dictionary-Fällen umgegangen wird. Was ist mit Funktionen? Dasselbe, aber wir verwenden zu diesem Zweck das Schlüsselwortargument mit den 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/except Muster übersät ist, um einfach 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 gültigen Wertesatzes liegt, als Teil der Daten in eine Datenstruktur eingefügt und zum Steuern und Testen spezieller Bedingungen (z. B. Grenzen, Status usw.) verwendet wird. Ein solcher Wert wird Sentinel genannt und kann so verwendet werden, wie None als Signal verwendet wird. Es ist trivial, in Python einen Sentinel zu erstellen.

undefined = object()

Das undefined -Objekt ist einzigartig und macht nicht viel von allem, was für ein Programm von Interesse sein könnte. Es ist daher ein hervorragender Ersatz für None als Flag. 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 Dikt

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 Gegenstand

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 bei benutzerdefinierten Sentinels einige Einschränkungen zu beachten. Erstens sind sie keine Schlüsselwörter wie None, daher schützt python sie nicht. Sie können Ihr undefined oben jederzeit an einer beliebigen Stelle im Modul überschreiben. Seien Sie also vorsichtig, wie Sie sie belichten und verwenden. Als nächstes ist die von object() zurückgegebene Instanz kein Singleton. Wenn Sie diesen Aufruf zehnmal ausführen, erhalten Sie zehn verschiedene Objekte. Schließlich ist die Verwendung eines Sentinels sehr eigenwillig. Ein Sentinel ist spezifisch für die Bibliothek, in der es verwendet wird, und daher sollte sein Umfang im Allgemeinen auf die internen Komponenten 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.

86
Michael Ekoka

Es heißt nicht wie in anderen Sprachen null, sondern None . Es gibt immer nur eine Instanz dieses Objekts, daher können Sie bei Bedarf die Übereinstimmung mit x is None (Identitätsvergleich) anstelle von x == None überprüfen.

63
AndiDog

In Python können Sie zur Darstellung des Fehlens eines Werts den Wert None ( types.NoneType.None verwenden ) für Objekte und "" (oder len () == 0 ) für Zeichenfolgen. 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 "is" jedoch als Objektidentitätsoperation definiert ist, ist es wahrscheinlich richtiger, sie zu verwenden, als "==". Ich bin mir nicht sicher, ob es überhaupt einen Geschwindigkeitsunterschied gibt.

Wie auch immer, Sie können einen Blick auf:

29
Paolo Rovelli

Per Truth value testing , 'None' testet direkt als FALSE, so dass der einfachste Ausdruck ausreicht:

if not foo:
0
artejera