189 votes

Comment dois-je utiliser l'indice de type facultatif ?

J'essaie de comprendre comment utiliser l'outil Optional indice de type. À partir de PEP-484 je sais que je peux utiliser Optional para def test(a: int = None) soit comme def test(a: Union[int, None]) o def test(a: Optional[int]) .

Mais qu'en est-il des exemples suivants ?

def test(a : dict = None):
    #print(a) ==> {'a': 1234}
    #or
    #print(a) ==> None

def test(a : list = None):
    #print(a) ==> [1,2,3,4, 'a', 'b']
    #or
    #print(a) ==> None

Si Optional[type] semble vouloir dire la même chose que Union[type, None] pourquoi devrais-je utiliser Optional[] du tout ?

1 votes

Quel est l'avantage d'utiliser Optional ou Union[..., None] plutôt que : list = None ? Cette syntaxe n'est-elle pas déjà explicite ?

2 votes

@gohu - Vous avez raison. Pour les arguments de mots-clés, les deux mypy et les IDE sont capables de supposer l'évidence et de les traiter automatiquement comme des Optional . Voir ma réponse ci-dessous.

290voto

Martijn Pieters Points 271458

Optional[...] est une notation abrégée pour Union[..., None] en indiquant au vérificateur de type qu'un objet du type spécifique est requis, o None est nécessaire. ... signifie tout indice de type valide y compris les types de composés complexes ou un Union[] de plus de types. Chaque fois que vous avez un argument de mot-clé avec une valeur par défaut None vous devez utiliser Optional . (Remarque : si vous utilisez Python 3.10 ou une version plus récente, PEP 604 a introduit une meilleure syntaxe, voir ci-dessous).

Donc pour vos deux exemples, vous avez dict y list mais la valeur par défaut de l'option a L'argument du mot-clé montre que None est également autorisé, alors utilisez Optional[...] :

from typing import Optional

def test(a: Optional[dict] = None) -> None:
    #print(a) ==> {'a': 1234}
    #or
    #print(a) ==> None

def test(a: Optional[list] = None) -> None:
    #print(a) ==> [1, 2, 3, 4, 'a', 'b']
    #or
    #print(a) ==> None

Il n'y a techniquement aucune différence entre l'utilisation de Optional[] sur un Union[] ou simplement en ajoutant None à la Union[] . Donc Optional[Union[str, int]] y Union[str, int, None] sont exactement la même chose.

Personnellement, je m'en tiendrais à toujours en utilisant Optional[] lors de la définition du type d'un argument de mot-clé qui utilise la fonction = None pour définir une valeur par défaut, ceci documente la raison pour laquelle None est mieux autorisée. En outre, il est plus facile de déplacer le Union[...] dans un alias de type distinct, ou pour supprimer ultérieurement l'élément Optional[...] partie si un argument devient obligatoire.

Par exemple, disons que vous avez

from typing import Optional, Union

def api_function(optional_argument: Optional[Union[str, int]] = None) -> None:
    """Frob the fooznar.

    If optional_argument is given, it must be an id of the fooznar subwidget
    to filter on. The id should be a string, or for backwards compatibility,
    an integer is also accepted.

    """

alors la documentation est améliorée en retirant le Union[str, int] en un alias de type :

from typing import Optional, Union

# subwidget ids used to be integers, now they are strings. Support both.
SubWidgetId = Union[str, int]

def api_function(optional_argument: Optional[SubWidgetId] = None) -> None:
    """Frob the fooznar.

    If optional_argument is given, it must be an id of the fooznar subwidget
    to filter on. The id should be a string, or for backwards compatibility,
    an integer is also accepted.

    """

Le remaniement visant à déplacer le Union[] en un alias a été rendu d'autant plus facile que Optional[...] a été utilisé à la place de Union[str, int, None] . Le site None n'est pas un "id de subwidget" après tout, il ne fait pas partie de la valeur, None est destiné à signaler l'absence d'une valeur.

Remarque : à moins que votre code ne doive supporter Python 3.9 ou une version plus récente, il est préférable d'éviter d'utiliser les types conteneurs de la bibliothèque standard dans les indications de type, car vous ne pouvez rien dire sur les types qu'ils doivent contenir. Ainsi, au lieu de dict y list utiliser typing.Dict y typing.List respectivement. Et lorsque seulement lecture d'un type de conteneur, vous pouvez tout aussi bien accepter n'importe quel type de conteneur abstrait immuable ; les listes et les tuples sont des Sequence tandis que dict es un Mapping type :

from typing import Mapping, Optional, Sequence, Union

def test(a: Optional[Mapping[str, int]] = None) -> None:
    """accepts an optional map with string keys and integer values"""
    # print(a) ==> {'a': 1234}
    # or
    # print(a) ==> None

def test(a: Optional[Sequence[Union[int, str]]] = None) -> None:
    """accepts an optional sequence of integers and strings
    # print(a) ==> [1, 2, 3, 4, 'a', 'b']
    # or
    # print(a) ==> None

À partir de la version 3.9 de Python, les types de conteneurs standard ont tous été mis à jour afin de pouvoir les utiliser dans les indications de type. PEP 585 . Mais alors que vous, maintenant peut utilice dict[str, int] o list[Union[int, str]] mais vous pouvez tout de même utiliser la méthode plus expressive Mapping y Sequence pour indiquer qu'une fonction ne modifiera pas le contenu (il sera traité comme étant en lecture seule) et que les fonctions fonctionneront avec des fichiers de type tout qui fonctionne comme un mappage ou une séquence, respectivement.

Python 3.10 introduit la fonction | l'opérateur d'union dans les indications de type, voir PEP 604 . Au lieu de Union[str, int] vous pouvez écrire str | int . En accord avec les autres langages à indication de type, la manière préférée (et plus concise) de désigner un argument optionnel dans Python 3.10 et plus est désormais la suivante Type | None par exemple str | None o list | None .

0 votes

@MartijnPieters Ne devons-nous pas importer Dict y List de taper et d'écrire Optional[Dict] y Optional[List] au lieu de Optional[dict] ...

0 votes

@Alireza oui, et je le précise déjà dans ma réponse. Cherchez : Remarque : vous devez éviter d'utiliser les types de conteneurs de la bibliothèque standard dans les indications de type, car vous ne pouvez rien dire sur les types qu'ils doivent contenir.

0 votes

Corrigez-moi si je me trompe, mais la version 3.9 autorise list y dict à utiliser pour les indications de type, (vs. List , Dict ). python.org/dev/peps/pep-0585

19voto

Directement à partir de docs sur le module de typage mypy .

  • " Optional[str] est juste un raccourci ou un alias pour Union[str, None]. Il existe principalement comme une commodité pour aider les signatures de fonctions à être un peu plus propres."

8voto

Troy Points 1372

Bien que la réponse acceptée soit la bonne, il convient de noter une chose supplémentaire, dans le cadre de kwargs les deux Optional[...] y Union[..., None] sont redondants et inutiles. Si vous réglez immédiatement votre kwarg sur None alors les deux mypy et les IDE supposent l'évidence et automatiquement traiter l'arg comme Optional[...] .

IDE :

enter image description here

mypy :

mypy automatic Optional

Pour les variables et les valeurs de retour des méthodes/fonctions, Optional[...] est cependant toujours nécessaire, car mypy ne peut pas savoir, dans ces cas-là, de supposer automatiquement quoi que ce soit.

-1voto

Alon Barad Points 420

Jusqu'à la version 3.9 de Python, si vous souhaitiez faire une recherche sur un fichier nullable valeur, vous aviez deux options :

import typing

def foo(bar: typing.Optional[str]):
    ....

def foo(bar: typing.Union[str, None]):
    ....

À partir de Python 3.9, vous n'êtes plus obligé d'utiliser le module de typage :

def foo(bar: str = None):
    ....

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