Comment vérifieriez-vous si une variable est un dictionnaire en Python?
Ceci est une excellente question, mais il est regrettable que la plupart des pistes de réponse upvoted avec une mauvaise recommandation, type(obj) is dict
.
(Notez que vous ne devez pas non plus l'utiliser dict
comme nom de variable - c'est le nom de l'objet intégré.)
Si vous écrivez du code qui sera importé et utilisé par d'autres, ne présumez pas qu'ils utiliseront directement le dict intégré - rendant cette présomption rend votre code plus rigide et dans ce cas, créez des bogues facilement cachés qui n'erreront pas le programme en erreur .
Je suggère fortement, à des fins d'exactitude, de maintenabilité et de flexibilité pour les futurs utilisateurs, de ne jamais avoir d'expressions unidiomatiques moins flexibles dans votre code lorsqu'il existe des expressions idiomatiques plus flexibles.
is
est un test d' identité d'objet . Il ne prend pas en charge l'héritage, il ne prend en charge aucune abstraction et il ne prend pas en charge l'interface.
Je vais donc fournir plusieurs options qui le font.
Soutenir l'héritage:
C'est la première recommandation que je voudrais faire, car elle permet aux utilisateurs de fournir leur propre sous - classe de dict, ou un OrderedDict
, defaultdict
ou Counter
des collections module:
if isinstance(any_object, dict):
Mais il existe des options encore plus flexibles.
Soutenir les abstractions:
from collections.abc import Mapping
if isinstance(any_object, Mapping):
Cela permet à l'utilisateur de votre code d'utiliser sa propre implémentation personnalisée d'un mappage abstrait, qui comprend également n'importe quelle sous-classe de dict
, tout en obtenant le comportement correct.
Utilisez l'interface
Vous entendez généralement les conseils de POO, "programme vers une interface".
Cette stratégie tire parti du polymorphisme ou du typage de canard de Python.
Il suffit donc d'essayer d'accéder à l'interface, d'attraper les erreurs spécifiques attendues ( AttributeError
au cas où il n'y en aurait pas .items
et TypeError
au cas où il ne items
serait pas possible de les appeler) avec un repli raisonnable - et maintenant, toute classe qui implémente cette interface vous donnera ses éléments (la note a .iteritems()
disparu en Python 3):
try:
items = any_object.items()
except (AttributeError, TypeError):
non_items_behavior(any_object)
else: # no exception raised
for item in items: ...
Peut-être pourriez-vous penser que l'utilisation de la saisie de canard comme celle-ci va trop loin en permettant trop de faux positifs, et cela peut l'être, selon vos objectifs pour ce code.
Conclusion
Ne pas utiliser is
pour vérifier les types de flux de contrôle standard. Utilisez isinstance
, envisagez des abstractions comme Mapping
ou MutableMapping
, et évitez complètement la vérification de type, en utilisant directement l'interface.