Réponses:
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:
...
None
, Null de Python?Il n'y a pas null
en 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 None
tant que valeur est d'utiliser l' is
opé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
None
None
est la seule instance de la classe NoneType
et toute autre tentative d'instanciation de cette classe retournera le même objet, ce qui fait None
un singleton. Les nouveaux venus sur Python voient souvent des messages d'erreur qui mentionnent NoneType
et se demandent ce que c'est. C'est mon opinion personnelle que ces messages pourraient simplement mentionner leur None
nom parce que, comme nous le verrons bientôt, None
laisse peu de place à l'ambiguïté. Donc, si vous voyez un TypeError
message qui mentionne que NoneType
vous ne pouvez pas faire ceci ou ne pouvez pas faire cela, sachez simplement que c'est simplement celui None
qui était utilisé d'une manière qu'il ne peut pas.
En outre, None
est 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. NoneType
en revanche, ce n'est pas le cas, vous devez d'abord obtenir une référence en interrogeant None
sa classe.
>>> NoneType
NameError: name 'NoneType' is not defined
>>> type(None)
NoneType
Vous pouvez vérifier None
l'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 None
références sont les mêmes. Il n'y a pas de "coutume" None
.
None
utilisation de l' is
opérateurLors 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.
None
pourquoi faire ceci
value is None
plutôt que
value==None
Le premier équivaut à:
id(value)==id(None)
Alors que l'expression value==None
est en fait appliquée comme ceci
value.__eq__(None)
si la valeur est vraiment, None
vous 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 None
et ç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
None
tant que booléenLes 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
None
est un "falsey", ce qui signifie que s'il est converti en booléen, il reviendra False
et s'il est appliqué à l' not
opérateur, il reviendra True
. Notez cependant que ce n'est pas une propriété unique à None
. En plus d' False
elle-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 pratiqueNone
utilisé comme valeur de signalNone
a 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 None
aux 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 None
lorsque 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 KeyError
se 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 valideLes utilisations décrites ci-dessus None
s'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ù None
vient 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 None
ne vous dit pas si l' attribut auquel vous tentiez d'accéder a été défini None
ou 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/except
construction:
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 valideSi vous trouvez que votre code est jonché du try/except
modèle ci-dessus simplement pour différencier les None
indicateurs et les None
donné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 None
qu’un signal. Il est trivial de créer une sentinelle en Python.
undefined = object()
L' undefined
objet ci-dessus est unique et ne fait pas grand-chose de ce qui pourrait intéresser un programme, c'est donc un excellent remplacement None
comme 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 undefined
ci - 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.
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.
None
. Ensuite, tous ces gens intelligents qui ont comparé contre NoneType
triompheront!
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:
0 == false
retour true
est que l'opérateur double-égal tape la contrainte. Avec l'opérateur triple-égal, cependant, 0 === false
renvoie false
, car «nombre» et «booléen» sont de types différents.
true
dans les conditions. Rust and Go, 0
et false
sont différents types qui ne peuvent pas être comparés pour l' égalité.
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
Par test de valeur de vérité , «Aucun» teste directement comme FAUX, donc l'expression la plus simple suffira:
if not foo:
True
pour toute valeur falsifiée, pas seulement None
.
egg is None
suregg == 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?) , toutis
en fonctionnant toujours de la même manière.