Comprendre l'objet NoneType de Python – Real Python

By | février 19, 2020

Formation Python

Si vous avez de l'expérience avec d'autres langages de programmation, comme C ou Java, alors vous avez probablement entendu parler du concept de nul. De nombreuses langues l'utilisent pour représenter un pointeur qui ne pointe vers rien, pour indiquer lorsqu'une variable est vide ou pour marquer des paramètres par défaut que vous n'avez pas encore fournis. nul est souvent défini comme 0 dans ces langues, mais nul en Python est différent.

Python utilise le mot clé Aucun définir nul objets et variables. Tandis que Aucun sert certains des mêmes objectifs que nul dans d'autres langues, c'est une autre bête entièrement. Comme le nul en Python, Aucun n'est pas défini pour être 0 ou toute autre valeur. En Python, Aucun est un objet et un citoyen de première classe!

Dans ce didacticiel, vous apprendrez:

  • Quoi Aucun est et comment le tester
  • Quand et pourquoi utiliser Aucun comme un paramètre par défaut
  • Quoi Aucun et AucunType dire dans votre traceback
  • Comment utiliser Aucun dans vérification de type
  • Comment nul en Python fonctionne sous le capot

Comprendre Null en Python

Aucun est la valeur renvoyée par une fonction en l'absence de revenir dans la fonction:

>>>

>>> def has_no_return():
...     passer
>>> has_no_return()
>>> impression(has_no_return())
Aucun

Quand vous appelez has_no_return (), il n'y a aucune sortie à voir. Lorsque vous lui imprimez un appel, cependant, vous verrez le Aucun il revient.

En réalité, Aucun apparaît si souvent comme valeur de retour que le Python REPL ne s'imprime pas Aucun sauf si vous le dites explicitement à:

>>>

>>> Aucun
>>> impression(Aucun)
Aucun

Aucun par lui-même n'a pas de sortie, mais l'impression affiche Aucun à la console.

De façon intéressante, impression() lui-même n'a aucune valeur de retour. Si vous essayez d'imprimer un appel vers impression(), vous obtiendrez Aucun:

>>>

>>> impression(impression("Bonjour le monde!"))
Bonjour le monde!
Aucun

Cela peut sembler étrange, mais imprimer (imprimer ("...")) vous montre le Aucun que l'intérieur impression() Retour.

Aucun également souvent utilisé comme signal pour paramètres manquants ou par défaut. Par exemple, Aucun apparaît deux fois dans les documents pour list.sort:

>>>

>>> Aidez-moi(liste.Trier)
Aide sur descripteur_méthode:

Trier(...)
                L.sort (key = None, reverse = False) -> None - tri stable * EN PLACE *

Ici, Aucun est la valeur par défaut du clé ainsi que l'indice de type pour la valeur de retour. La sortie exacte de Aidez-moi peut varier d'une plateforme à l'autre. Vous pouvez obtenir une sortie différente lorsque vous exécutez cette commande dans votre interpréteur, mais elle sera similaire.

Utilisation de l’objet nul de Python Aucun

Souvent, vous utiliserez Aucun dans le cadre d'une comparaison. Un exemple est lorsque vous devez vérifier et voir si un résultat ou un paramètre est Aucun. Prenez le résultat que vous obtenez re.match. Votre expression régulière correspondait-elle à une chaîne donnée? Vous verrez l'un des deux résultats:

  1. Renvoyer un Rencontre objet: Votre expression régulière a trouvé une correspondance.
  2. Renvoyer un Aucun objet: Votre expression régulière n'a pas trouvé de correspondance.

Dans le bloc de code ci-dessous, vous testez si le modèle "Au revoir" correspond à une chaîne:

>>>

>>> importation 
>>> rencontre = .rencontre(r"Au revoir", "Bonjour le monde!")
>>> si rencontre est Aucun:
...     impression("Ça ne correspond pas.")
Ça ne correspond pas.

Ici, vous utilisez est Aucun pour tester si le motif correspond à la chaîne "Bonjour le monde!". Ce bloc de code illustre une règle importante à garder à l'esprit lorsque vous recherchez Aucun:

  • Faire utiliser les opérateurs d'identité est et n'est pas.
  • Ne pas utiliser les opérateurs d'égalité == et ! =.

Les opérateurs d'égalité peuvent être dupés lorsque vous comparez des objets définis par l'utilisateur qui passer outre leur:

>>>

>>> classe BrokenComparison:
...     def __eq__(soi, autre):
...         revenir Vrai
>>> b = BrokenComparison()
>>> b == Aucun  # Opérateur d'égalité
Vrai
>>> b est Aucun  # Opérateur d'identité
Faux

Ici, l'opérateur d'égalité == renvoie la mauvaise réponse. L'opérateur d'identité est, d'autre part, ne peut pas être dupe parce que vous ne pouvez pas le remplacer.

Aucun est faux, ce qui signifie pas aucun est Vrai. Si tout ce que vous voulez savoir, c'est si un résultat est faux, alors un test comme le suivant est suffisant:

>>>

>>> some_result = Aucun
>>> si some_result:
...     impression("J'ai un résultat!")
... autre:
...     impression("Pas de résultat.")
...
Pas de résultat.

La sortie ne vous montre pas que some_result est exactement Aucun, seulement que c'est faux. Si vous devez savoir si vous avez ou non un Aucun objet, puis utilisez est et n'est pas.

Les objets suivants sont également tous faux:

Pour plus d'informations sur les comparaisons, les valeurs véridiques et fausses, consultez Comment utiliser le Python ou Opérateur.

Déclaration de variables nulles en Python

Dans certaines langues, les variables prennent vie déclaration. Il n'est pas nécessaire de leur attribuer une valeur initiale. Dans ces langues, la valeur par défaut initiale pour certains types de variables peut être nul. En Python, cependant, les variables prennent vie déclarations d'affectation. Jetez un œil au bloc de code suivant:

>>>

>>> impression(bar)
Traceback (dernier appel le plus récent):
  Fichier "", ligne 1, dans 
NameError: le nom 'bar' n'est pas défini
>>> bar = Aucun
>>> impression(bar)
Aucun

Ici, vous pouvez voir qu'une variable avec la valeur Aucun est différent d'une variable non définie. Toutes les variables en Python naissent par affectation. Une variable ne démarre que nul en Python si vous attribuez Aucun à elle.

En utilisant Aucun comme paramètre par défaut

Très souvent, vous utiliserez Aucun comme le valeur par défaut pour un paramètre facultatif. Il y a une très bonne raison d'utiliser Aucun ici plutôt qu'un type mutable tel qu'une liste. Imaginez une fonction comme celle-ci:

def mauvaise_fonction(new_elem, starter_list=[]):
    starter_list.ajouter(new_elem)
    revenir starter_list

bad_function () contient une mauvaise surprise. Cela fonctionne bien lorsque vous l'appelez avec une liste existante:

>>>

>>> ma liste = [[[['une', «b», «c»]
>>> mauvaise_fonction('ré', ma liste)
['a', 'b', 'c', 'd']

Ici, vous ajoutez sans problème «’ d »à la fin de la liste.

Mais si vous appelez cette fonction plusieurs fois sans starter_list , vous commencez à voir un comportement incorrect:

>>>

>>> mauvaise_fonction('une')
['a']
>>> mauvaise_fonction(«b»)
['a', 'b']
>>> mauvaise_fonction(«c»)
['a', 'b', 'c']

La valeur par défaut pour starter_list n'évalue qu'une seule fois au moment où la fonction est définie, de sorte que le code la réutilise chaque fois que vous ne passez pas une liste existante.

La bonne façon de construire cette fonction est d'utiliser Aucun comme valeur par défaut, puis testez-la et instanciez une nouvelle liste au besoin:

>>>

    1 >>> def bonne_fonction(new_elem, starter_list=Aucun):
    2 ...     si starter_list est Aucun:
    3 ...         starter_list = []
    4 ...     starter_list.ajouter(new_elem)
    5 ...     revenir starter_list
    6 ...
    sept >>> bonne_fonction(«e», ma liste)
    8 ['a', 'b', 'c', 'd', 'e']
    9 >>> bonne_fonction('une')
dix ['a']
11 >>> bonne_fonction(«b»)
12 ['b']
13 >>> bonne_fonction(«c»)
14 ['c']

good_function () se comporte comme vous le souhaitez en créant une nouvelle liste à chaque appel lorsque vous ne passez pas une liste existante. Cela fonctionne car votre code exécutera les lignes 2 et 3 à chaque fois qu'il appelle la fonction avec le paramètre par défaut.

En utilisant Aucun en tant que valeur nulle en Python

Qu'est-ce que vous faites quand Aucun est un objet d'entrée valide? Par exemple, si good_function () pourrait ajouter un élément à la liste ou non, et Aucun était un élément valide à ajouter? Dans ce cas, vous pouvez définir une classe spécifiquement pour une utilisation par défaut, tout en étant distincte de Aucun:

>>>

>>> classe DontAppend: passer
...
>>> def bonne_fonction(new_elem=DontAppend, starter_list=Aucun):
...     si starter_list est Aucun:
...         starter_list = []
...     si new_elem est ne pas DontAppend:
...         starter_list.ajouter(new_elem)
...     revenir starter_list
...
>>> bonne_fonction(starter_list=ma liste)
['a', 'b', 'c', 'd', 'e']
>>> bonne_fonction(Aucun, ma liste)
['a', 'b', 'c', 'd', 'e', None]

Ici, la classe DontAppend sert de signal à ne pas ajouter, vous n'avez donc pas besoin Aucun pour ça. Cela vous libère pour ajouter Aucun quand tu veux.

Vous pouvez utiliser cette technique lorsque Aucun est également une possibilité pour les valeurs de retour. Par exemple, dict.get Retour Aucun par défaut si aucune clé n'est trouvée dans le dictionnaire. Si Aucun était une valeur valide dans votre dictionnaire, vous pouvez appeler dict.get comme ça:

>>>

>>> classe Clé introuvable: passer
...
>>> my_dict = 'une':3, «b»:Aucun
>>> pour clé dans [[[['une', «b», «c»]:
...     valeur = my_dict.avoir(clé, Clé introuvable)
...     si valeur est ne pas Clé introuvable:
...         impression(F"clé->valeur")
...
a-> 3
b-> Aucun

Ici, vous avez défini une classe personnalisée Clé introuvable. Maintenant, au lieu de revenir Aucun lorsqu'une clé n'est pas dans le dictionnaire, vous pouvez retourner Clé introuvable. Cela vous libère pour revenir Aucun lorsque c'est la valeur réelle dans le dictionnaire.

Déchiffrer Aucun dans Tracebacks

Quand AucunType apparaît dans votre traceback, cela signifie que quelque chose que vous ne vous attendiez pas à Aucun était en fait Aucun, et vous avez essayé de l'utiliser d'une manière que vous ne pouvez pas utiliser Aucun. Presque toujours, c'est parce que vous essayez d'appeler une méthode dessus.

Par exemple, vous avez appelé ajouter() sur ma liste plusieurs fois ci-dessus, mais si ma liste en quelque sorte est devenu autre chose qu'une liste, puis ajouter() échouerait:

>>>

>>> ma liste.ajouter('F')
>>> ma liste
['a', 'b', 'c', 'd', 'e', None, 'f']
>>> ma liste = Aucun
>>> ma liste.ajouter('g')
Traceback (dernier appel le plus récent):
  Fichier "", ligne 1, dans 
AttributeError: L'objet 'NoneType' n'a pas d'attribut 'append'

Ici, votre code soulève le très commun AttributeError parce que l'objet sous-jacent, ma liste, n'est plus une liste. Vous l'avez réglé sur Aucun, qui ne sait pas comment ajouter(), et donc le code lève une exception.

Lorsque vous voyez un traceback comme celui-ci dans votre code, recherchez d'abord l'attribut qui a provoqué l'erreur. Et voilà ajouter(). De là, vous verrez l'objet sur lequel vous avez essayé de l'appeler. Dans ce cas, c'est ma liste, comme vous pouvez le constater à partir du code juste au-dessus du traceback. Enfin, découvrez comment cet objet est devenu Aucun et prenez les mesures nécessaires pour corriger votre code.

Recherche de null en Python

Il existe deux cas de vérification de type pour lesquels vous vous souciez nul en Python. Le premier cas, c'est quand vous revenez Aucun:

>>>

>>> def renvoie_aucun() -> Aucun:
...     passer

Ce cas est similaire à celui revenir instruction du tout, qui renvoie Aucun par défaut.

Le deuxième cas est un peu plus difficile. C'est là que vous prenez ou renvoyez une valeur qui pourrait être Aucun, mais peut également être un autre type (unique). Ce cas est comme ce que vous avez fait avec re.match ci-dessus, qui a renvoyé soit un Rencontre objet ou Aucun.

Le processus est similaire pour les paramètres:

de dactylographie importation Tout, liste, Optionnel
def bonne_fonction(new_elem:Tout, starter_list:Optionnel[[[[liste]=Aucun) -> liste:
    passer

Vous modifiez good_function () d'en haut et importation Optionnel de dactylographie retourner un Optionnel[Match].

Regarder sous le capot

Dans de nombreuses autres langues, nul est juste un synonyme de 0, mais nul en Python est un véritable objet:

>>>

>>> type(Aucun)

Cette ligne montre que Aucun est un objet, et son type est AucunType.

Aucun lui-même est intégré dans la langue en tant que nul en Python:

>>>

>>> dir(__builtins__)
['ArithmeticError', ..., 'None', ..., 'zip']

Içi vous pouvez voir Aucun dans la liste des __builtins__ qui est le dictionnaire que l'interprète conserve pour la intégrés module.

Aucun est un mot-clé, tout comme Vrai et Faux. Mais à cause de cela, vous ne pouvez pas atteindre Aucun directement de __builtins__ comme vous pourriez, par exemple, ArithmeticError. Cependant, vous pouvez l'obtenir avec un getattr () tour:

>>>

>>> __builtins__.ArithmeticError

>>> __builtins__.Aucun
  Fichier "", ligne 1
    __builtins__.Aucun
                    ^
Erreur de syntaxe: Syntaxe invalide
>>> impression(getattr(__builtins__, 'Aucun'))
Aucun

Lorsque vous utilisez getattr (), vous pouvez récupérer le Aucun de __builtins__, ce que vous ne pouvez pas faire en le demandant simplement avec __builtins __. Aucun.

Même si Python imprime le mot AucunType dans de nombreux messages d'erreur, AucunType n'est pas un identifiant en Python. Ce n'est pas dans intégrés. Vous ne pouvez l'atteindre qu'avec type (aucun).

Aucun est un singleton. C'est le AucunType classe ne vous donne que la même instance unique de Aucun. Il n'y en a qu'un Aucun dans votre programme Python:

>>>

>>> my_None = type(Aucun) ()  # Créer une nouvelle instance
>>> impression(my_None)
Aucun
>>> my_None est Aucun
Vrai

Même si vous essayez de créer une nouvelle instance, vous obtenez toujours l'existant Aucun.

Vous pouvez prouver que Aucun et my_None sont le même objet en utilisant id ():

>>>

>>> id(Aucun)
4465912088
>>> id(my_None)
4465912088

Ici, le fait que id renvoie la même valeur entière pour les deux Aucun et my_None signifie qu'ils sont, en fait, le même objet.

Si vous essayez d'affecter à Aucun, vous obtiendrez un Erreur de syntaxe:

>>>

>>> Aucun = 5
Traceback (dernier appel le plus récent):
  Fichier "", ligne 1, dans 
Erreur de syntaxe: impossible d'attribuer au mot clé
>>> Aucun.âge = 5
Traceback (dernier appel le plus récent):
  Fichier "", ligne 1, dans 
AttributeError: L'objet 'NoneType' n'a pas d'attribut 'age'
>>> setattr(Aucun, 'âge', 5)
Traceback (dernier appel le plus récent):
  Fichier "", ligne 1, dans 
AttributeError: L'objet 'NoneType' n'a pas d'attribut 'age'
>>> setattr(type(Aucun), 'âge', 5)
Traceback (dernier appel le plus récent):
  Fichier "", ligne 1, dans 
Erreur-type: impossible de définir les attributs de type intégré / d'extension 'NoneType'

Tous les exemples ci-dessus montrent que vous ne pouvez pas modifier Aucun ou AucunType. Ce sont de vraies constantes.

Vous ne pouvez pas sous-classe AucunType, Soit:

>>>

>>> classe MyNoneType(type(Aucun)):
...     passer
...
Traceback (dernier appel le plus récent):
  Fichier "", ligne 1, dans 
Erreur-type: le type «NoneType» n'est pas un type de base acceptable

Ce retraçage montre que l'interprète ne vous laissera pas créer une nouvelle classe qui hérite de type (aucun).

Conclusion

Aucun est un outil puissant dans la boîte à outils Python. Comme Vrai et Faux, Aucun est un mot-clé immuable. Comme le nul en Python, vous l'utilisez pour marquer des valeurs et des résultats manquants, et même des paramètres par défaut où c'est un bien meilleur choix que les types mutables.

Maintenant vous pouvez:

  • Test pour Aucun avec est et n'est pas
  • Choisissez quand Aucun est une valeur valide dans votre code
  • Utilisation Aucun et ses alternatives comme paramètres par défaut
  • Déchiffrer Aucun et AucunType dans vos traces
  • Utilisation Aucun et Optionnel dans les indices de type

Comment utilisez-vous le nul en Python? Laissez un commentaire dans la section commentaires ci-dessous!