objet nul en Python?

1194

Comment faire référence à l'objet null en Python?

Lézard
la source

Réponses:

1630

En Python, l'objet 'null' est le singleton None.

La meilleure façon de vérifier les choses pour « Noneness » est d'utiliser l'opérateur d'identité, is:

if foo is None:
    ...
Ben James
la source
126
Et la raison du choix egg is Nonesur egg == None: Ce dernier peut être surchargée, et est susceptible de se briser lorsque l'on compare objet valide avec aucun (dépend de la façon dont il est mis en œuvre, mais vous ne vous attendez pas à tout le monde de prendre comparisions avec aucun compte, pensez - vous?) , tout isen fonctionnant toujours de la même manière.
94
pourquoi les concepteurs de python n'ont-ils pas simplement choisi "null". Il suffit d'être différent, n'est-ce pas! ;)
Vidar
35
@Vidar 'None' n'est pas un manque d'objet (comme 'null' est, une référence null), c'est un objet réel. Vous n'obtiendrez jamais un objet «None» passant pour un objet qui est d'un type autre que «NoneType». Ce n'est pas non plus un concept de langage. Il n'est pas intégré à Python, il fait partie de la bibliothèque standard de Python. Aucun! == (ahem) Null
Rushyo
11
@ naught101 Cela ne servirait à rien; car il n'y a pas de concept de pointeurs. Si vous utilisez la bibliothèque ctypes, None sera utilisé comme synonyme de l'adresse zéro mais il n'y a toujours pas de concept de langage de «référence nulle». En Python, vous avez toujours laissé référence à une sorte d'objet, même si cet objet est None. Je soupçonne que cela simplifie considérablement la langue.
Rushyo
5
grande présentation expliquant «l'erreur du milliard de dollars» qui est la référence nulle: infoq.com/presentations/… . Les autres options au lieu de null sont les types Options ou Peut-être (personnalisés).
Michael Trouw
136

None, Null de Python?

Il n'y a pas nullen Python, au lieu de cela None. Comme indiqué précédemment, la manière la plus précise de tester que quelque chose a été donné en Nonetant que valeur est d'utiliser l' isopérateur d'identité, qui teste que deux variables se réfèrent au même objet.

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

Les bases

Il n'y en a et ne peut y en avoir qu'un None

Noneest la seule instance de la classe NoneTypeet toute autre tentative d'instanciation de cette classe retournera le même objet, ce qui fait Noneun singleton. Les nouveaux venus sur Python voient souvent des messages d'erreur qui mentionnent NoneTypeet se demandent ce que c'est. C'est mon opinion personnelle que ces messages pourraient simplement mentionner leur Nonenom parce que, comme nous le verrons bientôt, Nonelaisse peu de place à l'ambiguïté. Donc, si vous voyez un TypeErrormessage qui mentionne que NoneTypevous ne pouvez pas faire ceci ou ne pouvez pas faire cela, sachez simplement que c'est simplement celui Nonequi était utilisé d'une manière qu'il ne peut pas.

En outre, Noneest une constante intégrée, dès que vous démarrez Python, elle est disponible pour être utilisée de partout, que ce soit dans un module, une classe ou une fonction. NoneTypeen revanche, ce n'est pas le cas, vous devez d'abord obtenir une référence en interrogeant Nonesa classe.

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

Vous pouvez vérifier Nonel'unicité de la fonction d'identité de Python id(). Il renvoie le numéro unique attribué à un objet, chaque objet en a un. Si l'id de deux variables est le même, alors elles pointent en fait vers le même objet.

>>> 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 ne peut pas être écrasé

Dans une version beaucoup plus ancienne de Python (avant 2.4), il était possible de réaffecter None, mais plus maintenant. Pas même en tant qu'attribut de classe ou dans les limites d'une fonction.

# 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

Il est donc prudent de supposer que toutes les Noneréférences sont les mêmes. Il n'y a pas de "coutume" None.

Pour tester l' Noneutilisation de l' isopérateur

Lors de l'écriture de code, vous pourriez être tenté de tester la non- existence comme ceci:

if value==None:
    pass

Ou pour tester le mensonge comme celui-ci

if not value:
    pass

Vous devez comprendre les implications et pourquoi c'est souvent une bonne idée d'être explicite.

Cas 1: tester si une valeur est None

pourquoi faire ceci

value is None

plutôt que

value==None

Le premier équivaut à:

id(value)==id(None)

Alors que l'expression value==Noneest en fait appliquée comme ceci

value.__eq__(None)

si la valeur est vraiment, Nonevous obtiendrez ce que vous attendiez.

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

Dans la plupart des cas, le résultat sera le même, mais la __eq__()méthode ouvre une porte qui annule toute garantie de précision, car elle peut être remplacée dans une classe pour fournir un comportement spécial.

Considérez cette classe.

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

Donc vous l'essayez Noneet ça marche

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

Mais cela fonctionne aussi sur la chaîne vide

>>> empty==''
True

Et pourtant

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

Cas 2: Utilisation en Nonetant que booléen

Les deux tests suivants

if value:
    # do something

if not value:
    # do something

sont en fait évalués comme

if bool(value):
    # do something

if not bool(value):
    # do something

Noneest un "falsey", ce qui signifie que s'il est converti en booléen, il reviendra Falseet s'il est appliqué à l' notopérateur, il reviendra True. Notez cependant que ce n'est pas une propriété unique à None. En plus d' Falseelle-même, la propriété est partagée par des listes vides, des tuples, des ensembles, des dict, des chaînes, ainsi que 0, et tous les objets des classes qui implémentent la __bool__()méthode magique à renvoyer 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

Ainsi, lorsque vous testez des variables de la manière suivante, soyez très conscient de ce que vous incluez ou excluez du test:

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

Dans ce qui précède, vouliez-vous appeler init_value()lorsque la valeur est définie spécifiquement sur None, ou vouliez-vous qu'une valeur définie sur 0, ou la chaîne vide, ou une liste vide devrait également déclencher l'initialisation. Comme je l'ai dit, soyez conscient. Comme c'est souvent le cas en Python, explicite vaut mieux qu'implicite .

None en pratique

None utilisé comme valeur de signal

Nonea un statut spécial en Python. C'est une valeur de référence préférée car de nombreux algorithmes la traitent comme une valeur exceptionnelle. Dans de tels scénarios, il peut être utilisé comme indicateur pour signaler qu'une condition nécessite une gestion particulière (comme la définition d'une valeur par défaut).

Vous pouvez attribuer Noneaux mots clés des arguments d'une fonction, puis les tester explicitement.

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

Vous pouvez le renvoyer par défaut lorsque vous essayez d'accéder à l'attribut d'un objet, puis le tester explicitement avant de faire quelque chose de spécial.

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

Par défaut, la get()méthode d' un dictionnaire renvoie Nonelorsque vous essayez d'accéder à une clé non existante:

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

Si vous deviez essayer d'y accéder en utilisant la notation d' un indice KeyErrorse poseraient

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

De même, si vous essayez de faire apparaître un élément inexistant

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

que vous pouvez supprimer avec une valeur par défaut qui est généralement définie sur None

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

None utilisé à la fois comme indicateur et comme valeur valide

Les utilisations décrites ci-dessus Nones'appliquent lorsque ce n'est pas considéré comme une valeur valide, mais plutôt comme un signal pour faire quelque chose de spécial. Il y a cependant des situations où il est parfois important de savoir d'où Nonevient car même s'il est utilisé comme signal, il peut également faire partie des données.

Lorsque vous interrogez un objet pour son attribut, getattr(some_obj, 'attribute_name', None)le retour Nonene vous dit pas si l' attribut auquel vous tentiez d'accéder a été défini Noneou s'il était totalement absent de l'objet. Même situation lors de l'accès à une clé à partir d'un dictionnaire comme some_dict.get('some_key'), vous ne savez pas si elle some_dict['some_key']est manquante ou si elle est juste définie sur None. Si vous avez besoin de ces informations, la manière habituelle de gérer cela est d'essayer directement d'accéder à l'attribut ou à la clé à partir d'une try/exceptconstruction:

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)

De même avec 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)

Les deux exemples ci-dessus montrent comment gérer les cas d'objets et de dictionnaire, qu'en est-il des fonctions? Même chose, mais nous utilisons à cet effet l'argument du mot-clé double astérisques:

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 utilisé uniquement comme valeur valide

Si vous trouvez que votre code est jonché du try/exceptmodèle ci-dessus simplement pour différencier les Noneindicateurs et les Nonedonnées, utilisez simplement une autre valeur de test. Il existe un modèle dans lequel une valeur qui ne fait pas partie de l'ensemble de valeurs valides est insérée en tant que partie des données dans une structure de données et est utilisée pour contrôler et tester des conditions spéciales (par exemple, limites, état, etc.). Une telle valeur est appelée sentinelle et elle peut être utilisée de la même manière Nonequ’un signal. Il est trivial de créer une sentinelle en Python.

undefined = object()

L' undefinedobjet ci-dessus est unique et ne fait pas grand-chose de ce qui pourrait intéresser un programme, c'est donc un excellent remplacement Nonecomme drapeau. Certaines mises en garde s'appliquent, plus à ce sujet après le code.

Avec fonction

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

Avec 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

Avec un objet

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

Comme je l'ai mentionné plus tôt, les sentinelles personnalisées comportent certaines mises en garde. Tout d'abord, ce ne sont pas des mots-clés None, donc python ne les protège pas. Vous pouvez remplacer votre undefinedci - dessus à tout moment, n'importe où dans le module défini, alors faites attention à la façon dont vous les exposez et les utilisez. Ensuite, l'instance renvoyée par object()n'est pas un singleton, si vous effectuez cet appel 10 fois, vous obtenez 10 objets différents. Enfin, l'utilisation d'une sentinelle est hautement idiosyncrasique. Une sentinelle est spécifique à la bibliothèque dans laquelle elle est utilisée et, en tant que telle, sa portée doit généralement être limitée aux éléments internes de la bibliothèque. Il ne devrait pas "fuir". Le code externe ne doit en prendre connaissance que si son but est d'étendre ou de compléter l'API de la bibliothèque.

Michael Ekoka
la source
Qu'en est-il de: Aucune == chose?
hkBst
@hkBst Je suppose que votre question concerne la façon dont python évalue l'égalité. Jetez un œil à ce stackoverflow.com/questions/3588776/…
Michael Ekoka
Ah, donc IIUC qui habituellement finira toujours par appeler chose .__ eq__? Dans ce cas, je retire ma suggestion.
hkBst
@MichaelEkoka pouvez-vous partager la source de ces informations impressionnantes et utiles.
Anidhya Bhatnagar
Pratique standard. Vous pouvez en trouver quelques indices en passant par le didacticiel Python , mais la lecture du code source des projets populaires est mon premier conseil pour vous immerger rapidement dans Python idiomatique .
Michael Ekoka
67

Ce n'est pas appelé null comme dans d'autres langues, mais None. Il n'y a toujours qu'une seule instance de cet objet, vous pouvez donc vérifier l'équivalence avec x is None(comparaison d'identité) au lieu de x == None, si vous le souhaitez.

AndiDog
la source
25
Je vais trouver un moyen de casser Python en réinstanciant None. Ensuite, tous ces gens intelligents qui ont comparé contre NoneTypetriompheront!
Zenexer
28

En Python, pour représenter l'absence de valeur, vous pouvez utiliser la valeur None ( types.NoneType.None ) pour les objets et "" (ou len () == 0 ) pour les chaînes. Donc:

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

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

En ce qui concerne la différence entre "==" et "is", le test d'identité d'objet à l'aide de "==" devrait être suffisant. Cependant, puisque l'opération "is" est définie comme l'opération d'identité d'objet, il est probablement plus correct de l'utiliser plutôt que "==". Je ne sais pas s'il y a même une différence de vitesse.

Quoi qu'il en soit, vous pouvez consulter:

Paolo Rovelli
la source
8
Pour autant que je sache, (0 == false) renvoie vrai DANS CHAQUE langage de programmation. C'est parce que false est codé comme 0 et "true" comme tout ce qui n'est PAS 0. Cependant, veuillez noter que l'opérateur "is" n'est pas le même que celui "==". C'est plus ou moins la même différence entre "==" et "égal" en Java. L'opérateur "est", en effet, vérifie si DEUX OBJETS sont les mêmes (la même instance et PAS le même contenu)!
Paolo Rovelli
12
Paolo, FYI, (0 == false) ne renvoie pas true dans tous les langages de programmation. Un exemple de compteur rapide serait Scala, où (0 == false) renvoie false, et je suis sûr que Scala n'est pas le seul langage de programmation qui renvoie false lors de la comparaison d'un nombre avec un booléen.
Rob Wilton
2
Ok, j'ai compris! Ensuite, disons dans la plupart des langages de programmation.
Paolo Rovelli
3
En JavaScript, la raison du 0 == falseretour trueest que l'opérateur double-égal tape la contrainte. Avec l'opérateur triple-égal, cependant, 0 === falserenvoie false, car «nombre» et «booléen» sont de types différents.
jkdev
1
@PaoloRovelli, dans Lua, Ruby et Clojure, 0 est traité comme truedans les conditions. Rust and Go, 0et false sont différents types qui ne peuvent pas être comparés pour l' égalité.
scooter-dangle
0

Null est un type d'objet spécial comme:

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

Vous pouvez vérifier si un objet est dans la classe 'NoneType':

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

Plus d'informations sont disponibles sur Python Docs


la source
-1

Par test de valeur de vérité , «Aucun» teste directement comme FAUX, donc l'expression la plus simple suffira:

if not foo:
artejera
la source
3
Non, ce ne sera pas le cas. Cette expression reviendra Truepour toute valeur falsifiée, pas seulement None.
insert_name_here
Vrai, et le simple "sinon foo:" ne répondrait pas correctement à la question d'origine, comme indiqué. Cependant, python est typé dynamiquement et invite à réduire les protocoles de syntaxe, il me semble donc valide, de considérer des constructions plus simples et similaires.
artejera