Disons que j'ai un python fonction dont l'argument unique est un type non trivial:
from typing import List, Dict
ArgType = List[Dict[str, int]] # this could be any non-trivial type
def myfun(a: ArgType) -> None:
...
... Et puis j'ai une structure de données que j'ai déballée à partir d'une source JSON:
import json
data = json.loads(...)
Ma question est la suivante: Comment puis-je vérifier au moment de l'exécution que data
a le type correct à utiliser comme argument à myfun()
Avant l'utiliser comme argument pour myfun()
?
if not isCorrectType(data, ArgType):
raise TypeError("data is not correct type")
else:
myfun(data)
Le moyen courant de gérer cela consiste à utiliser le fait que si quel que soit l'objet que vous passez à myfun
_ n'a pas la fonctionnalité requise une exception correspondante sera soulevée (généralement TypeError
ou AttributeError
). Donc, vous feriez ce qui suit:
try:
myfun(data)
except (TypeError, AttributeError) as err:
# Fallback for invalid types here.
Vous indiquez dans votre question que vous allumeriez un TypeError
si l'objet transcuté n'a pas la structure appropriée, mais Python le fait déjà pour vous. La question critique est la façon dont vous voulez gérer ce cas. Vous pouvez également déplacer le try / except
bloquer dans myfun
, le cas échéant. Quand il s'agit de taper Python vous comptez habituellement sur dactylographie de canard : Si l'objet a la fonctionnalité requise, vous ne vous souciez pas beaucoup de ce type de type, Tant que cela sert le but.
Considérez l'exemple suivant. Nous venons de transmettre les données dans la fonction, puis d'obtenir le AttributeError
gratuitement (que nous pouvons alors sauf); Pas besoin de vérification de type manuel:
>>> def myfun(data):
... for x in data:
... print(x.items())
...
>>> data = json.loads('[[["a", 1], ["b", 2]], [["c", 3], ["d", 4]]]')
>>> myfun(data)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in myfun
AttributeError: 'list' object has no attribute 'items'
Si vous êtes préoccupé par l'utilité de l'erreur résultante, vous pouvez toujours sauf re-élever une exception personnalisée (ou même changer le message de l'exception):
try:
myfun(data)
except (TypeError, AttributeError) as err:
raise TypeError('Data has incorrect structure') from err
try:
myfun(data)
except (TypeError, AttributeError) as err:
err.args = ('Data has incorrect structure',)
raise
Lorsque vous utilisez le code tiers, il faut toujours vérifier la documentation des exceptions qui seront soulevées. Par exemple numpy.inner
rapporte qu'il augmentera un ValueError
dans certaines circonstances. Lorsque vous utilisez cette fonction, nous n'avons pas besoin d'effectuer nous-mêmes des chèques, mais s'appuie sur le fait qu'il augmentera l'erreur si nécessaire. Lorsque vous utilisez un code tiers pour lequel il n'est pas clair comment il se comportera dans certains cas d'angle, c'est-à-dire Il est plus facile et plus clair pour simplement coder un vérificateur de type correspondant (voir ci-dessous) au lieu d'utiliser une solution générique qui fonctionne pour n'importe quel type. Ces cas devraient être rares de toute façon et laisser un commentaire correspondant rend vos collègues développeurs au courant de la situation.
La bibliothèque typing
est destinée à l'allusion de type et à ce titre, il ne vérifiera pas les types d'exécution. Bien sûr, vous pourriez le faire manuellement, mais c'est plutôt encombrant:
def type_checker(data):
return (
isinstance(data, list)
and all(isinstance(x, dict) for x in list)
and all(isinstance(k, str) and isinstance(v, int) for x in list for k, v in x.items())
)
Ceci avec un commentaire approprié est toujours une solution acceptable et il est réutilisable lorsqu'une structure de données similaire est attendue. L'intention est claire et le code est facilement vérifiable.
C'est gênant qu'il n'y a pas de fonction intégrée pour cela, mais typeguard
est livré avec une fonction pratique check_type()
:
>>> from typeguard import check_type
>>> from typing import List
>>> check_type("foo", [1,2,"3"], List[int])
Traceback (most recent call last):
...
TypeError: type of foo[2] must be int; got str instead
type of foo[2] must be int; got str instead
Pour plus, voir: https://typeguard.readthedocs.io/fr/latest/api.html#typeguard.check_type
Vous devriez vérifier manuellement votre structure de type imbriquée manuellement - le type d'indice n'est pas appliqué.
Vérification de ce type de choses IST MEILLEUR FAIT en utilisant ABC (CLASSES ABSJECTES META) - Les utilisateurs peuvent donc fournir leurs classes dérivées qui prennent en charge le même accès/listes par défaut:
import collections.abc
def isCorrectType(data):
if isinstance(data, collections.abc.Collection):
for d in data:
if isinstance(d,collections.abc.MutableMapping):
for key in d:
if isinstance(key,str) and isinstance(d[key],int):
pass
else:
return False
else:
return False
else:
return False
return True
Sortir:
print ( isCorrectType( [ {"a":2} ] )) # True
print ( isCorrectType( [ {2:2} ] )) # False
print ( isCorrectType( [ {"a":"a"} ] )) # False
print ( isCorrectType( [ {"a":2},1 ] )) # False
Doku:
En rapport:
L'autre sens serait de suivre la "Demander le pardon non autorisée" - Expliquez Paradigm et Simyply Utilisez Vos données dans le formulaire que vous voulez et try:/except:
autour si cela ne se conforme pas à ce que vous vouliez. Cela correspond mieux avec Qu'est-ce que le dactylographie de canard? - et permet (semblable à ABC-Vérification), le consommateur de vous fournir des cours dérivés de la liste/dict pendant qu'il fonctionnera toujours ...