web-dev-qa-db-fra.com

Quelle exception dois-je déclencher sur les combinaisons d’arguments incorrectes / illégales en Python?

Je m'interrogeais sur les meilleures pratiques pour indiquer des combinaisons d'arguments non valides en Python. J'ai rencontré quelques situations où vous avez une fonction comme celle-ci:

def import_to_orm(name, save=False, recurse=False):
    """
    :param name: Name of some external entity to import.
    :param save: Save the ORM object before returning.
    :param recurse: Attempt to import associated objects as well. Because you
        need the original object to have a key to relate to, save must be
        `True` for recurse to be `True`.
    :raise BadValueError: If `recurse and not save`.
    :return: The ORM object.
    """
    pass

Le seul inconvénient, c’est que chaque paquet a son propre, généralement légèrement différent BadValueError. Je sais que dans Java il existe Java.lang.IllegalArgumentException - est-il bien compris que tout le monde va créer son propre BadValueErrors dans Python ou y en a-t-il un autre, de préférence méthode?

473
cdleary

Je voudrais juste soulever ValueError , sauf si vous avez besoin d'une exception plus spécifique.

def import_to_orm(name, save=False, recurse=False):
    if recurse and not save:
        raise ValueError("save must be True if recurse is True")

Il n'y a vraiment aucun intérêt à faire class BadValueError(ValueError):pass - votre classe personnalisée est identique en utilisation à ValueError , alors pourquoi ne pas l'utiliser?

521
dbr

Je hériterais de ValueError

class IllegalArgumentError(ValueError):
    pass

Il est parfois préférable de créer vos propres exceptions, tout en héritant d’une exception intégrée, qui soit aussi proche que possible de ce que vous voulez.

Si vous devez détecter cette erreur spécifique, il est utile d’avoir un nom.

94
Markus Jarderot

Je pense que la meilleure façon de gérer cela est la façon dont python lui-même le gère. Python déclenche une TypeError. Par exemple:

$ python -c 'print(sum())'
Traceback (most recent call last):
File "<string>", line 1, in <module>
TypeError: sum expected at least 1 arguments, got 0

Notre développeur junior vient de trouver cette page dans une recherche Google pour "arguments erronés à l'exception de python" et je suis surpris que la réponse évidente (pour moi) n'ait pas été suggérée au cours de la décennie écoulée depuis que cette question a été posée.

11
J Bones

La plupart du temps, je viens de voir le ValueError intégré utilisé dans cette situation.

9
Eli Courtwright

Cela dépend de quel est le problème avec les arguments.

Si le type de l'argument est incorrect, déclenche une erreur TypeError. Par exemple, lorsque vous obtenez une chaîne au lieu d'un de ces booléens.

if not isinstance(save, bool):
    raise TypeError(f"Argument save must be of type bool, not {type(save)}")

Notez cependant que dans Python, nous effectuons rarement des vérifications de ce type. Si l'argument est vraiment invalide, une fonction plus profonde fera probablement la plainte pour nous. Et si nous ne vérifions que la valeur booléenne, un utilisateur de code lui fournira peut-être une chaîne plus tard, en sachant que les chaînes non vides sont toujours True. Cela pourrait lui sauver un casting.

Si les arguments ont des valeurs non valides, déclenchez ValueError. Cela semble plus approprié dans votre cas:

if recurse and not save:
    raise ValueError("If recurse is True, save should be True too")

Ou dans ce cas spécifique, une valeur True de recurse implique une valeur True de save. Étant donné que je considérerais cela comme une reprise après une erreur, vous pouvez également vouloir vous plaindre dans le journal.

if recurse and not save:
    logging.warning("Bad arguments in import_to_orm() - if recurse is True, so should save be")
    save = True
1
Jacco van Dorp

Je ne suis pas sûr d'être d'accord avec l'héritage de ValueError - mon interprétation de la documentation est que ValueError est seulement supposé être élevé par des éléments intégrés ... en hériter ou en l'élevant vous-même semble incorrect.

Lancé lorsqu'une opération ou une fonction intégrée reçoit un argument ayant le type correct, mais une valeur inappropriée, et la situation n'est pas décrite par une exception plus précise, telle que IndexError.

- documentation ValueError

1
cdleary

Acceptez la suggestion de Markus de lancer votre propre exception, mais le texte de l’exception devrait préciser que le problème se situe dans la liste des arguments, et non dans les valeurs des arguments individuels. Je proposerais:

class BadCallError(ValueError):
    pass

Utilisé lorsqu'il manque des arguments de mot clé requis pour l'appel spécifique ou lorsque les valeurs d'argument sont individuellement valides mais incohérentes. ValueError aurait toujours raison lorsqu'un argument spécifique est de type correct mais hors limites.

Cela ne devrait-il pas être une exception standard en Python?

En général, j'aimerais que le style Python soit un peu plus net pour distinguer les entrées incorrectes d'une fonction (faute de l'appelant) des résultats incorrects dans la fonction (ma faute). Donc, il peut également y avoir une BadArgumentError pour distinguer les erreurs de valeur dans les arguments des erreurs de valeur dans les paramètres locaux.

0
BobHy