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 BadValueError
s dans Python ou y en a-t-il un autre, de préférence méthode?
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?
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.
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.
La plupart du temps, je viens de voir le ValueError
intégré utilisé dans cette situation.
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
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.
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.