144 votes

Qu'est-ce qu'une valeur None ?

J'ai étudié Python et j'ai lu un chapitre qui décrit la valeur None, mais malheureusement ce livre n'est pas très clair à certains points. Je pensais que je trouverais la réponse à ma question, si je la partageais ici.

Je veux savoir ce que la valeur None est et à quoi sert-elle?

Et aussi, je ne comprends pas cette partie du livre :

Affecter une valeur de None à une variable est une façon de la réinitialiser à son état original et vide.

Qu'est-ce que cela signifie?

Les réponses étaient géniales, bien que je n'ai pas compris la plupart des réponses en raison de mes faibles connaissances du monde informatique (je n'ai pas appris sur les classes, les objets, etc.). Que signifie cette phrase?

Affecter une valeur de None à une variable est une façon de la réinitialiser à son état original et vide.

En conclusion :

Finalement, j'ai obtenu ma réponse en regardant différentes réponses. Je dois apprécier toutes les personnes qui ont pris le temps de m'aider (surtout Martijn Pieters et DSM), et j'aimerais pouvoir choisir toutes les réponses comme étant les meilleures, mais la sélection est limitée à une. Toutes les réponses étaient formidables.

116voto

DSM Points 71975

La réponse de Martijn explique ce qu'est None en Python, et affirme correctement que le livre est trompeur. Comme les programmeurs Python ne diraient jamais par principe

Attribuer une valeur de None à une variable est une façon de la réinitialiser à son état initial, vide.

il est difficile d'expliquer ce que Briggs veut dire d'une manière qui ait du sens et explique pourquoi personne ici n'en est satisfait. Une analogie qui peut aider:

En Python, les noms de variables sont comme des autocollants collés sur des objets. Chaque autocollant a un nom unique écrit dessus, et il ne peut être collé que sur un seul objet à la fois, mais vous pourriez coller plus d'un autocollant sur le même objet, si vous le voulez. Lorsque vous écrivez

F = "fourchette"

vous collez l'autocollant "F" sur un objet chaîne "fourchette". Si vous écrivez ensuite

F = None

vous déplacez l'autocollant vers l'objet None.

Ce que Briggs vous demande d'imaginer, c'est que vous n'avez pas écrit l'autocollant "F", il y avait déjà un autocollant F sur le None, et tout ce que vous avez fait était de le déplacer, de None à "fourchette". Donc lorsque vous tapez F = None, vous "réinitialisez" à son état initial, si nous décidions de considérer None comme signifiant état vide.

Je vois ce qu'il veut dire, mais c'est une mauvaise façon de le voir. Si vous démarrez Python et tapez print(F), vous verrez

>>> print(F)
Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'F' is not defined

et cette NameError signifie que Python ne reconnaît pas le nom F, car il n'y a pas un tel autocollant. Si Briggs avait raison et que F = None réinitialise F à son état initial, alors il devrait être là maintenant, et nous devrions voir

>>> print(F)
None

comme nous le faisons après avoir tape F = None et collé l'autocollant sur None.


Voilà ce qu'il se passe. En réalité, Python est livré avec certains autocollants déjà attachés aux objets (noms intégrés), mais d'autres vous devez les écrire vous-même avec des lignes comme F = "fourchette" et A = 2 et c17 = 3.14, puis vous pouvez les coller sur d'autres objets plus tard (comme F = 10 ou F = None; tout est pareil.)

Briggs prétend que tous les autocollants possibles que vous pourriez vouloir écrire étaient déjà collés à l'objet None.

73voto

Martijn Pieters Points 271458

Aucun est simplement une valeur qui est couramment utilisée pour signifier 'vide' ou 'aucune valeur ici'. C'est un objet signal; il n'a de sens que parce que la documentation Python dit qu'il a cette signification.

Il n'y a qu'une seule copie de cet objet dans une session donnée de l'interpréteur Python.

Si vous écrivez une fonction et que cette fonction n'utilise pas une instruction return explicite, Aucun est retourné à la place, par exemple. De cette façon, la programmation avec des fonctions est beaucoup simplifiée; une fonction retourne toujours quelque chose, même si c'est juste cet objet Aucun.

Vous pouvez le tester de manière explicite:

if foo is None:
    # foo est défini sur Aucun

if bar is not None:
    # bar est défini sur quelque chose *autre* que Aucun

Une autre utilisation est de donner des paramètres facultatifs aux fonctions avec une valeur par défaut 'vide':

def spam(foo=None):
    if foo is not None:
        # foo a été spécifié, faites quelque chose d'astucieux!

La fonction spam() a un argument facultatif; si vous appelez spam() sans le spécifier, la valeur par défaut Aucun lui est donnée, ce qui facilite la détection si la fonction a été appelée avec un argument ou non.

D'autres langues ont des concepts similaires. SQL a NULL; JavaScript a undefined et null, etc.

Remarquez qu'en Python, les variables existent par le simple fait d'être utilisées. Vous n'avez pas besoin de déclarer une variable d'abord, donc il n'y a pas vraiment de variables vides en Python. Définir une variable sur Aucun n'est donc pas la même chose que de la définir sur une valeur vide par défaut; Aucun est aussi une valeur, bien que souvent utilisée pour signaler le vide. Le livre que vous lisez est trompeur sur ce point.

26voto

thefourtheye Points 56958

C'est ce que la documentation Python a à dire sur None:

La seule valeur de types.NoneType. None est fréquemment utilisé pour représenter l'absence d'une valeur, comme lorsque des arguments par défaut ne sont pas passés à une fonction.

Modifié dans la version 2.4: Les affectations à None sont illégales et lèvent une SyntaxError.

Remarque: Les noms None et debug ne peuvent pas être réattribués (les affectations à eux, même en tant que nom d'attribut, lèvent une SyntaxError), ils peuvent donc être considérés comme des "vraies" constantes.

  1. Vérifions d'abord le type de None

    print type(None)
    print None.__class__

    Sortie

Essentiellement, NoneType est un type de données tout comme int, float, etc. Vous pouvez consulter la liste des types par défaut disponibles en Python dans 8.15. types — Noms des types intégrés.

  1. Et, None est une instance de la classe NoneType. Donc nous pourrions vouloir créer des instances de None nous-mêmes. Essayons cela

    print types.IntType()
    print types.NoneType()

    Sortie

    0
    TypeError: ne peut pas créer d'instances de 'NoneType'

Il est clair que nous ne pouvons pas créer d'instances de NoneType. Nous n'avons pas à nous soucier de l'unicité de la valeur None.

  1. Vérifions comment nous avons implémenté None en interne.

    print dir(None)

    Sortie

    ['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', 
     '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__',
     '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

À l'exception de __setattr__, tous les autres attributs sont en lecture seule. Ainsi, il n'y a aucun moyen de modifier les attributs de None.

  1. Essayons d'ajouter de nouveaux attributs à None

    setattr(types.NoneType, 'somefield', 'somevalue')
    setattr(None, 'somefield', 'somevalue')
    None.somefield = 'somevalue'

    Sortie

    TypeError: impossible de définir des attributs du type 'NoneType' intégré/extension
    AttributeError: l'objet 'NoneType' n'a pas d'attribut 'somefield'
    AttributeError: l'objet 'NoneType' n'a pas d'attribut 'somefield'

Les déclarations ci-dessus génèrent ces messages d'erreur, respectivement. Cela signifie que nous ne pouvons pas créer dynamiquement des attributs sur une instance de None.

  1. Voyons ce qui se passe lorsque nous assignons quelque chose à None. Selon la documentation, cela devrait déclencher une SyntaxError. Cela signifie que si nous attribuons quelque chose à None, le programme ne sera pas exécuté du tout.

    None = 1

    Sortie

    SyntaxError: impossible d'attribuer à None

Nous avons établi que

  1. None est une instance de la classe NoneType
  2. None ne peut pas avoir de nouveaux attributs
  3. Les attributs existants de None ne peuvent pas être modifiés.
  4. Nous ne pouvons pas créer d'autres instances de NoneType
  5. Nous ne pouvons même pas modifier la référence à None en lui attribuant des valeurs.

Ainsi, comme mentionné dans la documentation, None peut vraiment être considéré comme une vraie constante.

Heureusement de connaître None :)

12voto

kojiro Points 24374

Le livre auquel vous vous référez tente clairement de simplifier grandement le sens de None. Les variables Python n'ont pas un état initial vide - les variables Python sont liées (uniquement) lorsqu'elles sont définies. Vous ne pouvez pas créer une variable Python sans lui donner une valeur.

>>> print(x)
Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'x' is not defined
>>> def test(x):
...   print(x)
... 
>>> test()
Traceback (most recent call last):
  File "", line 1, in 
TypeError: test() takes exactly 1 argument (0 given)
>>> def test():
...   print(x)
... 
>>> test()
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 2, in test
NameError: global name 'x' is not defined

mais parfois, vous voulez que fonction signifie des choses différentes en fonction de si une variable est définie ou non. Vous pouvez créer un argument avec une valeur par défaut de None:

>>> def test(x=None):
...   if x is None:
...     print('pas de x ici')
...   else:
...     print(x)
... 
>>> test()
pas de x ici
>>> test('x!')
x!

Le fait que cette valeur soit la valeur spéciale None n'est pas très important dans ce cas. J'aurais pu utiliser n'importe quelle valeur par défaut:

>>> def test(x=-1):
...   if x == -1:
...     print('pas de x ici')
...   else:
...     print(x)
... 
>>> test()
pas de x ici
>>> test('x!')
x!

... mais avoir None nous offre deux avantages:

  1. Nous n'avons pas à choisir une valeur spéciale comme -1 dont la signification n'est pas claire, et
  2. Notre fonction peut éventuellement avoir besoin de traiter -1 comme une entrée normale.

    test(-1) pas de x ici

oups!

Donc le livre est un peu trompeur principalement dans son utilisation du mot réinitialiser – assigner None à un nom est un signal pour un programmeur que cette valeur n'est pas utilisée ou que la fonction doit se comporter d'une manière par défaut, mais pour réinitialiser une valeur à son état original, non défini, vous devez utiliser le mot-clé del:

>>> x = 3
>>> x
3
>>> del x
>>> x
Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'x' is not defined

7voto

Jadav Points 536

D'autres réponses ont déjà expliqué le sens de Aucun de manière magnifique. Cependant, j'aimerais encore apporter plus de lumière à ce sujet en utilisant un exemple.

Exemple :

def extendList(val, list=[]):
    list.append(val)
    return list

list1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList('a')

print "list1 = %s" % list1
print "list2 = %s" % list2
print "list3 = %s" % list3

Essayez maintenant de deviner la sortie de la liste ci-dessus. Eh bien, la réponse est étonnamment la suivante :

list1 = [10, 'a']
list2 = [123]
list3 = [10, 'a']

Mais Pourquoi ?

Beaucoup s'attendent à tort à ce que list1 soit égal à [10] et list3 soit égal à ['a'], en pensant que l'argument de liste sera défini sur sa valeur par défaut de [] à chaque appel de extendList.

Cependant, ce qui se passe en réalité est que la nouvelle liste par défaut n'est créée qu'une seule fois lorsque la fonction est définie, et cette même liste est ensuite utilisée systématiquement chaque fois que extendList est appelée sans spécifier d'argument de liste. Cela est dû au fait que les expressions dans les arguments par défaut sont calculées lorsque la fonction est définie, et non lors de son appel.

list1 et list3 opèrent donc sur la même liste par défaut, tandis que list2 opère sur une liste séparée qu'il a créée (en passant sa propre liste vide comme valeur pour le paramètre de liste).


'Aucun' le sauveur : (Modifier l'exemple ci-dessus pour produire le comportement souhaité)

def extendList(val, list=None):
    if list is None:
       list = []
    list.append(val)
    return list

list1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList('a')

print "list1 = %s" % list1
print "list2 = %s" % list2
print "list3 = %s" % list3

Avec cette implémentation révisée, la sortie serait :

list1 = [10]
list2 = [123]
list3 = ['a']

Remarque - Crédit de l'exemple à toptal.com

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X