Question objet nul en Python?


Comment puis-je faire référence à l'objet nul en Python?


804
2017-07-20 11:53


origine


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:
    ...

1119
2017-07-20 11:54



Il 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 tu veux.


53
2017-07-20 11:56



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

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

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

En ce qui concerne la différence entre "==" et "est", tester l'identité de l'objet en utilisant "==" devrait suffire. Cependant, puisque l'opération "est" 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 jeter un oeil à:


26
2018-03-03 11:11



None, Null de Python?

Il n'y a pas null en Python, à la place il y a None. Comme indiqué déjà la façon la plus précise de tester que quelque chose a été donné None comme une valeur est d'utiliser le 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

Les bases

Il y a et peut seulement être un None

None est la seule instance de la classe NoneType et toute autre tentative d'instancier cette classe retournera le même objet, ce qui rend None un singleton. Les nouveaux arrivants à Python voient souvent des messages d'erreur qui mentionnent NoneType et je me demande ce que c'est. C'est mon opinion personnelle que ces messages pourraient simplement mentionner None par son nom parce que, comme nous le verrons bientôt, None laisse peu de place à l'ambiguïté. Donc, si vous en voyez TypeError un message qui mentionne que NoneType ne peut pas faire cela ou ne peut pas le faire, sachez simplement que c'est simplement celui None c'était utilisé d'une manière qui ne le peut pas.

Aussi, None est une constante intégrée, dès que vous démarrez Python, il est disponible à utiliser de partout, que ce soit dans le module, la classe ou la fonction. NoneType en revanche, ce n'est pas le cas, vous devez d'abord y faire référence en interrogeant None pour sa classe.

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

Tu peux vérifier Nonel'unicité avec la fonction d'identité de Python id(). Il renvoie le numéro unique attribué à un objet, chaque objet en a un. Si l'identifiant de deux variables est le même, ils pointent en fait sur 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 tous None les références sont les mêmes. Il n'y a pas de "coutume" None.

Pour tester None Utilisez le is opérateur

Lorsque vous écrivez du code, vous pourriez être tenté de tester Noneness comme ça:

if value==None:
    pass

Ou pour tester le mensonge comme ça

if not value:
    pass

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

Cas 1: test si une valeur est None

pourquoi faire ceci

value is None

plutôt que

value==None

Le premier est équivalent à:

id(value)==id(None)

Alors que l'expression value==None est en fait appliqué comme ça

value.__eq__(None)

si la valeur est vraiment None alors vous aurez 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 le __eq__() méthode ouvre une porte qui annule toute garantie de précision, car elle peut être outrepassée dans une classe pour fournir un comportement spécial.

Considérez cette classe.

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

Alors vous l'essayez None et il fonctionne

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

Mais alors cela fonctionne aussi sur la chaîne vide

>>> empty==''
True

Et encore

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

Cas 2: Utilisation None comme un 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

None est un "falsey", ce qui signifie que s'il est converti en un booléen, il reviendra False et si elle est appliquée not opérateur, il reviendra True. Notez cependant que ce n'est pas une propriété unique à None. En plus de False elle-même, la propriété est partagée par des listes vides, des tuples, des ensembles, des dicts, des chaînes, ainsi que par 0, et tous les objets des classes implémentant le __bool__() méthode magique pour revenir 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 plus attentif à 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, avez-vous l'intention d'appeler init_value() lorsque la valeur est définie spécifiquement pour None, ou vouliez-vous dire qu'une valeur fixée à 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 est meilleur que implicite.

None en pratique

None utilisé comme valeur de signal

None a un statut spécial en Python. C'est une valeur de référence préférée car beaucoup d'algorithmes la considèrent comme une valeur exceptionnelle. Dans de tels scénarios, il peut être utilisé comme un indicateur pour signaler qu'une condition nécessite un traitement spécial (comme le réglage d'une valeur par défaut).

Vous pouvez assigner None au mot-clé arguments d'une fonction et ensuite le 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, un dictionnaire get() retour de méthode 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 indice un KeyError serait élevé

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

De même, si vous tentez de faire apparaître un objet non existant

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

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

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

None utilisé comme drapeau et valeur valide

Les utilisations décrites ci-dessus de None appliquer quand il n'est pas considéré comme une valeur valide, mais plus comme un signal pour faire quelque chose de spécial. Il y a cependant des situations où il est parfois important de savoir où None est venu parce que même si c'est utilisé comme un signal, il pourrait également faire partie des données.

Lorsque vous interrogez un objet pour son attribut avec getattr(some_obj, 'attribute_name', None) revenir None ne vous dit pas si l'attribut auquel vous essayez d'accéder a été défini sur None ou si elle était complètement absente de l'objet. Même situation lors de l'accès à une clé à partir d'un dictionnaire comme some_dict.get('some_key'), tu ne sais pas si some_dict['some_key'] est manquant ou si c'est juste mis à 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'un 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 dictionnaires, qu'en est-il des fonctions? Même chose, mais nous utilisons l'argument du mot clé double asterisks à cette fin:

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é seulement comme une valeur valide

Si vous trouvez que votre code est jonché de ce qui précède try/except modèle simplement pour différencier entre None drapeaux et None données, puis utilisez simplement une autre valeur de test. Il existe un motif dans lequel une valeur qui ne correspond pas à l'ensemble des valeurs valides est insérée dans les données d'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 ça peut être utilisé comme ça None est utilisé comme un signal. Il est trivial de créer une sentinelle en Python.

undefined = object()

le undefined l'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 pour None comme un 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 sentinelles personnalisées viennent avec quelques mises en garde. Premièrement, ils ne sont pas des mots-clés comme None, donc python ne les protège pas. Vous pouvez écraser votre undefined ci-dessus à tout moment, n'importe où dans le module il est 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 faites cet appel 10 fois vous obtenez 10 objets différents. Enfin, l'utilisation d'une sentinelle est hautement idiosyncratique. Une sentinelle est spécifique à la bibliothèque dans laquelle elle est utilisée et, en tant que telle, sa portée devrait généralement être limitée aux internes de la bibliothèque. Il ne devrait pas "couler". Le code externe ne devrait en prendre connaissance que s'il a pour but d'étendre ou de compléter l'API de la bibliothèque.


26
2018-01-29 15:34



Par Test de valeur de vérité, 'None' teste directement comme FALSE, donc l'expression la plus simple suffira:

if not foo:

0
2017-09-24 23:15