variable - python string none




Null-Objekt in Python? (4)

None , Pythons Null?

In Python gibt es keine null , stattdessen gibt es None . Wie bereits erwähnt, ist der genaueste Weg, um zu testen, dass etwas als Wert angegeben wurde, der Is-Operator, der prüft, ob zwei Variablen auf dasselbe Objekt verweisen.

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

Die Grundlagen

Es gibt und kann nur eins sein

None ist die einzige Instanz der Klasse NoneType und alle weiteren Versuche, diese Klasse zu instanziieren, werden dasselbe Objekt zurückgeben, das None einem Singleton macht. Neuankömmlinge in Python sehen oft Fehlermeldungen, die NoneType erwähnen und fragen sich, was es ist. Es ist meine persönliche Meinung, dass diese Nachrichten einfach None namentlich erwähnen könnten, weil, wie wir in Kürze sehen werden, None Raum für Ambiguität lässt. Wenn Sie also eine TypeError Nachricht sehen, die darauf NoneType , dass NoneType dies nicht kann oder nicht kann, dann wissen Sie einfach, dass es einfach die None , die auf eine Weise verwendet wurde, die nicht verwendet werden kann.

Außerdem ist None eine eingebaute Konstante, sobald Sie Python starten, ist es für die Verwendung von überall verfügbar, egal ob in Modul, Klasse oder Funktion. NoneType dagegen ist nicht, Sie müssten zuerst einen Verweis darauf erhalten, indem Sie None für seine Klasse abfragen.

>>> 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 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 einer viel älteren Version von Python (vor 2.4) war es möglich, None neu 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 davon auszugehen, dass alle None Referenzen gleich sind. Es gibt keine "benutzerdefinierte" None .

Um auf None zu prüfen, verwenden Sie den Operator is

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

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 None

warum tu das?

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 None dann erhalten Sie, 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 keine Garantie für die Genauigkeit gibt, da sie in einer Klasse außer Kraft gesetzt werden kann, um ein besonderes Verhalten zu bieten.

Betrachten Sie diese Klasse.

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

Also versuchst du es auf 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 von None als Boolean

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 False zurückgibt und wenn es auf den not Operator angewendet wird, wird es True . Beachten Sie jedoch, dass es sich nicht um eine Eigenschaft handelt, die nur für " None . Zusätzlich zu False selbst wird die Eigenschaft von leeren Listen, Tupeln, Mengen, Dicts, Strings sowie 0 und allen Objekten von Klassen geteilt, 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

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()

init_value() Sie im obigen init_value() aufrufen, wenn der Wert speziell auf None , oder init_value() Sie, dass ein Wert, der auf 0 , oder die leere Zeichenfolge oder eine leere Liste auch die Initialisierung auslösen soll. Wie gesagt, sei achtsam. Wie es oft in Python der Fall ist, ist Explizit besser als Implizit .

None in der Praxis

None als Signalwert verwendet

None hat in Python einen besonderen Status. 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 den Schlüsselwortargumenten einer Funktion None zuweisen und dann explizit danach suchen.

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 gibt get() Methode get() eines Wörterbuchs 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 KeyError würde ein KeyError 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 None

value = some_dict.pop('foo', None)
if value is None:
    # booom!

None als Flag und gültiger Wert verwendet

Die oben beschriebenen Anwendungen von None gelten, wenn sie nicht als gültiger Wert betrachtet werden, sondern eher als ein Signal, etwas Besonderes zu tun. Es gibt jedoch Situationen, in denen es manchmal wichtig ist zu wissen, woher None kommen, denn obwohl es als Signal verwendet wird, könnte es auch Teil der Daten sein.

Wenn Sie ein Objekt für sein Attribut mit getattr(some_obj, 'attribute_name', None) erhalten Sie zurück. None sagt Ihnen nicht, ob das Attribut, auf das Sie getattr(some_obj, 'attribute_name', None) auf None oder ob 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') , Sie wissen nicht, ob some_dict['some_key'] fehlt oder ob es nur auf None . Wenn Sie diese Informationen benötigen, besteht die übliche Vorgehensweise darin, direkt auf das Attribut oder den Schlüssel innerhalb eines try/except Konstrukts 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 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 zu diesem Zweck:

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, try/except 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 der Menge gültiger Werte liegt, als Teil der Daten in einer Datenstruktur eingefügt wird und dazu dient, spezielle Bedingungen (z. B. Grenzen, Status usw.) zu steuern und zu testen. 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 oben undefined Objekt ist einzigartig und macht nicht viel von allem, was für ein Programm von Interesse sein könnte, es ist somit ein ausgezeichneter Ersatz für None als Flagge. 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 Schlüsselwörter wie " None , also schützt Python sie nicht. Sie können Ihre undefined Datei jederzeit und überall in dem definierten Modul überschreiben. Seien Sie also vorsichtig, wie Sie sie bereitstellen und verwenden. Als nächstes ist die von object() Instanz 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 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.

Wie verweise ich auf das Null-Objekt in Python?


Es heißt nicht null wie in anderen Sprachen, aber None . Es gibt immer nur eine Instanz dieses Objekts. Sie können also nach Äquivalenz suchen, wobei x is None (Identitätsvergleich) anstelle von x == None , wenn Sie möchten.


Um in Python die Abwesenheit eines Werts darzustellen, können Sie den None- Wert ( types.NoneType.None ) für Objekte und "" (oder len () == 0 ) für Strings verwenden. 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:


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

Der beste Weg, Dinge auf "Noneness" zu prüfen, ist die Verwendung des Identity-Operators.

if foo is None:
    ...






null