oggetto null in Python?


1193

Come posso fare riferimento all'oggetto null in Python?

Risposte:


1629

In Python, l'oggetto "null" è il singleton None.

Il modo migliore per controllare le cose per "Noneness" è usare l'operatore di identità is:

if foo is None:
    ...

126
E la ragione per la scelta di egg is Nonesopra egg == None: Quest'ultimo può essere sovraccaricato, e rischia di rompersi quando si confrontano oggetto valido con Nessuno (dipende da come è implementato, ma che non ti aspetti a tutti di prendere comparazioni con nessuno in considerazione, vero?) , mentre isfunziona sempre allo stesso modo.

94
perché i designer di Python non hanno semplicemente scelto "null"? Devi solo essere diverso, vero? ;)
Vidar il

35
@Vidar 'Nessuno' non è una mancanza di un oggetto (come è 'null', un riferimento null), è un oggetto reale. Non otterrai mai un oggetto "Nessuno" che passa per un oggetto di un tipo diverso da "Nessuno". Inoltre non è un concetto di linguaggio .. Non è incorporato in Python il linguaggio, fa parte della libreria standard di Python. Nessuno! == (ahem) Null
Rushyo

11
@ naught101 Non servirebbe a nulla; in quanto non esiste un concetto di puntatori. Se si utilizza la libreria ctypes, Nessuno verrà utilizzato come sinonimo dell'indirizzo zero ma non esiste ancora il concetto di linguaggio di un "riferimento null". In Python, hai sempre lasciato riferimento a qualche tipo di oggetto, anche se quell'oggetto è Nessuno. Sospetto che ciò semplifichi notevolmente la lingua.
Rushyo,

5
grande presentazione che spiega l '"errore del miliardo di dollari" che è il riferimento null: infoq.com/presentations/… . Altre opzioni anziché null sono Opzioni o Tipi forse (personalizzati).
Michael Trouw,

135

None, Null di Python?

Non c'è nullin Python, invece c'è None. Come già affermato, il modo più accurato per verificare che qualcosa sia stato dato Nonecome valore è utilizzare l' isoperatore di identità, che verifica che due variabili si riferiscano allo stesso oggetto.

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

Le basi

C'è e può essercene solo uno None

Noneè la sola istanza della classe NoneTypee ogni ulteriore tentativo di istanziare quella classe restituirà lo stesso oggetto, il che rende Noneun singleton. I nuovi arrivati ​​in Python vedono spesso messaggi di errore che menzionano NoneTypee si chiedono di cosa si tratti. È mia opinione personale che questi messaggi possano semplicemente menzionare Noneper nome perché, come vedremo tra poco, Nonelascia poco spazio all'ambiguità. Quindi se vedi qualche TypeErrormessaggio che menziona che NoneTypenon può farlo o non puoi farlo, sappi solo che è semplicemente quello Noneche veniva usato in un modo che non può.

Inoltre, Noneè una costante incorporata, non appena avvii Python è disponibile per l'uso da qualsiasi luogo, sia in modulo, classe o funzione. NoneTypeal contrario no, dovresti prima ottenere un riferimento ad esso eseguendo Noneuna query per la sua classe.

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

Puoi verificare Nonel'unicità con la funzione di identità di Python id(). Restituisce il numero univoco assegnato a un oggetto, ogni oggetto ne ha uno. Se l'id di due variabili è lo stesso, indicano in realtà lo stesso oggetto.

>>> 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 non può essere sovrascritto

Nella versione molto più vecchia di Python (prima della 2.4) era possibile riassegnare None, ma non più. Nemmeno come attributo di classe o nei confini di una funzione.

# 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

È quindi sicuro presumere che tutti i Noneriferimenti siano uguali. Non c'è "personalizzato" None.

Per testare l' Noneuso isdell'operatore

Quando scrivi il codice potresti essere tentato di provare Noneness in questo modo:

if value==None:
    pass

O per verificare la presenza di falsità come questa

if not value:
    pass

Devi capire le implicazioni e perché spesso è una buona idea essere espliciti.

Caso 1: verifica se un valore è None

perché farlo

value is None

piuttosto che

value==None

Il primo equivale a:

id(value)==id(None)

Considerando che l'espressione value==Noneè infatti applicata in questo modo

value.__eq__(None)

se il valore è davvero None, otterrai quello che ti aspettavi.

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

Nella maggior parte dei casi il risultato sarà lo stesso, ma il __eq__()metodo apre una porta che annulla qualsiasi garanzia di accuratezza, poiché può essere ignorato in una classe per fornire un comportamento speciale.

Considera questa classe.

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

Quindi lo provi Nonee funziona

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

Ma poi funziona anche sulla stringa vuota

>>> empty==''
True

E ancora

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

Caso 2: utilizzo Nonecome booleano

I seguenti due test

if value:
    # do something

if not value:
    # do something

sono infatti valutati come

if bool(value):
    # do something

if not bool(value):
    # do something

Noneè un "falso", il che significa che se lanciato su un valore booleano ritornerà Falsee se applicato l' notoperatore tornerà True. Si noti tuttavia che non è una proprietà unica per None. Oltre a Falsese stesso, la proprietà è condivisa da liste vuote, tuple, set, dadi, stringhe, nonché da 0, e da tutti gli oggetti delle classi che implementano il __bool__()metodo magico per restituire 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

Pertanto, quando si esegue il test delle variabili nel modo seguente, prestare particolare attenzione a ciò che si sta includendo o escludendo dal test:

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

In quanto sopra, intendevi chiamare init_value()quando il valore è impostato in modo specifico su None, oppure intendevi che un valore impostato su 0, o la stringa vuota o un elenco vuoto dovrebbe attivare anche l'inizializzazione. Come ho detto, sii consapevole. Come spesso accade in Python esplicito è meglio che implicito .

None in pratica

None utilizzato come valore del segnale

Noneha uno status speciale in Python. È un valore di base preferito perché molti algoritmi lo trattano come un valore eccezionale. In tali scenari può essere utilizzato come flag per segnalare che una condizione richiede una gestione speciale (come l'impostazione di un valore predefinito).

È possibile assegnare Noneagli argomenti della parola chiave di una funzione e quindi testarlo esplicitamente.

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

È possibile restituirlo come predefinito quando si cerca di ottenere l'attributo di un oggetto e quindi testarlo esplicitamente prima di fare qualcosa di speciale.

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

Per impostazione predefinita, il get()metodo di un dizionario ritorna Nonequando si tenta di accedere a una chiave inesistente:

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

Se dovessi provare ad accedervi usando la notazione in pedice a KeyErrorverrebbe sollevato

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

Allo stesso modo se si tenta di far apparire un oggetto inesistente

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

che è possibile eliminare con un valore predefinito generalmente impostato su None

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

None usato sia come flag che come valore valido

Gli usi sopra descritti si Noneapplicano quando non è considerato un valore valido, ma più come un segnale per fare qualcosa di speciale. Esistono tuttavia situazioni in cui a volte è importante sapere da dove Noneprovengono perché anche se viene utilizzato come segnale potrebbe anche essere parte dei dati.

Quando si interroga un oggetto per il suo attributo con il getattr(some_obj, 'attribute_name', None)recupero, Nonenon viene indicato se l'attributo a cui si stava tentando di accedere era impostato Noneo se era del tutto assente dall'oggetto. Stessa situazione quando si accede a una chiave da un dizionario come some_dict.get('some_key'), non si sa se some_dict['some_key']manca o se è appena impostato su None. Se hai bisogno di tali informazioni, il solito modo di gestirle è tentare direttamente di accedere all'attributo o alla chiave all'interno di un try/exceptcostrutto:

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)

Allo stesso modo con 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)

I due esempi precedenti mostrano come gestire i casi di oggetto e dizionario, che dire delle funzioni? Stessa cosa, ma usiamo l'argomento della doppia parola chiave asterischi a tal fine:

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 usato solo come valore valido

Se scopri che il tuo codice è disseminato del try/exceptmodello sopra semplicemente per differenziare tra Noneflag e Nonedati, usa semplicemente un altro valore di test. Esiste un modello in cui un valore che non rientra nel set di valori validi viene inserito come parte dei dati in una struttura di dati e viene utilizzato per controllare e testare condizioni speciali (ad es. Confini, stato, ecc.). Tale valore è chiamato sentinella e può essere utilizzato come modo Noneviene utilizzato come segnale. È banale creare una sentinella in Python.

undefined = object()

L' undefinedoggetto sopra è unico e non fa molto di tutto ciò che potrebbe interessare un programma, è quindi un eccellente sostituto di Nonecome bandiera. Si applicano alcuni avvertimenti, ulteriori informazioni dopo il codice.

Con la funzione

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

Con 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

Con un oggetto

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

Come ho già detto, le sentinelle personalizzate vengono fornite con alcuni avvertimenti. Innanzitutto, non sono parole chiave come None, quindi Python non le protegge. Puoi sovrascrivere il tuo undefinedsopra in qualsiasi momento, ovunque nel modulo sia definito, quindi fai attenzione a come li esponi e li usi. Successivamente, l'istanza restituita da object()non è un singleton, se si effettua quella chiamata 10 volte si ottengono 10 oggetti diversi. Infine, l'uso di una sentinella è altamente idiosincratico. Una sentinella è specifica della libreria in cui viene utilizzata e come tale il suo ambito dovrebbe generalmente essere limitato agli interni della libreria. Non dovrebbe "fuoriuscire". Il codice esterno dovrebbe prenderne conoscenza solo se il loro scopo è di estendere o integrare l'API della libreria.


Che dire: nessuna == cosa?
hk

@hkBst Immagino che la tua domanda sia su come Python valuta l'uguaglianza. Date un'occhiata a questo stackoverflow.com/questions/3588776/...
Michael Ekoka

Ah, quindi IIUC che di solito finisce per chiamare cosa .__ eq__? In tal caso ritiro il mio suggerimento.
hk

@MichaelEkoka puoi condividere la fonte per queste informazioni impressionanti e utili.
Anidhya Bhatnagar il

Pratica standard. Puoi trovare alcuni suggerimenti a riguardo durante l' esercitazione su Python , ma leggere il codice sorgente di progetti popolari è il mio consiglio numero uno per immergerti rapidamente in Python idiomatico .
Michael Ekoka,

67

Non si chiama null come in altre lingue, ma None. Esiste sempre solo un'istanza di questo oggetto, quindi puoi verificare l'equivalenza con x is None(confronto delle identità) anziché x == None, se lo desideri.


25
Troverò un modo per spezzare Python ri-istanziando None. Quindi NoneTypetrionferanno tutte quelle persone intelligenti che hanno confrontato contro !
Zenexer,

28

In Python, per rappresentare l'assenza di un valore, è possibile utilizzare il valore None ( types.NoneType.None ) per gli oggetti e "" (o len () == 0 ) per le stringhe. Perciò:

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

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

Per quanto riguarda la differenza tra "==" e "is", il test per l'identità dell'oggetto utilizzando "==" dovrebbe essere sufficiente. Tuttavia, poiché l'operazione "is" è definita come operazione di identità dell'oggetto, è probabilmente più corretto utilizzarla, anziché "==". Non sono sicuro che ci sia anche una differenza di velocità.

Ad ogni modo, puoi dare un'occhiata a:


8
Per quanto ne so, (0 == false) restituisce true IN OGNI linguaggio di programmazione. Questo perché false è codificato come 0 e "true" come tutto ciò che NON è 0. Tuttavia, si prega di non notare che l'operatore "is" non è lo stesso di "==". Questa è più o meno la stessa differenza tra "==" e "uguale" in Java. L'operatore "è", infatti, controlla se DUE OGGETTI sono uguali (la stessa istanza e NON lo stesso contenuto)!
Paolo Rovelli,

12
Paolo, FYI, (0 == false) non restituisce true in tutti i linguaggi di programmazione. Un rapido esempio di contatore sarebbe Scala, dove (0 == false) restituisce false, e sono sicuro che Scala non è l'unico linguaggio di programmazione che restituisce false quando si confronta un numero con un valore booleano.
Rob Wilton,

2
Ok capito! Quindi, diciamo nella maggior parte dei linguaggi di programmazione.
Paolo Rovelli,

3
In JavaScript, il motivo 0 == falserestituito trueè perché l'operatore double-equal digita la coercizione. Con l'operatore triple-egals, tuttavia, 0 === falserestituisce false, poiché "numero" e "booleano" sono tipi diversi.
jkdev,

1
@PaoloRovelli, in Lua, Ruby e Clojure, 0 viene trattato come truein condizionali. In Rust and Go, 0e false sono diversi tipi che non possono essere confrontati per l'uguaglianza.
scooter ciondola il

0

Null è un tipo di oggetto speciale come:

>>>type(None)
<class 'NoneType'>

Puoi verificare se un oggetto è nella classe 'NoneType':

>>>variable = None
>>>variable is None
True

Ulteriori informazioni sono disponibili su Python Docs


-1

Per il test del valore di Verità , "Nessuno" verifica direttamente come FALSO, quindi sarà sufficiente l'espressione più semplice:

if not foo:

3
No, non lo farà. Quell'espressione tornerà Trueper qualsiasi valore falsy, e non solo None.
insert_name_here

Vero, e il semplice "if not foo:" non risponderebbe correttamente alla domanda originale, come affermato. Tuttavia, python è tipizzato in modo dinamico e invita a ridurre i protocolli di sintassi, quindi mi sembra valido, considerare costrutti più semplici e simili.
artejera,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.