Come verifichi se una variabile è un dizionario in Python?
Questa è un'ottima domanda, ma è un peccato che la risposta più votata porti a una cattiva raccomandazione type(obj) is dict
.
(Nota che non dovresti usare anche dict
come nome di variabile - è il nome dell'oggetto incorporato.)
Se stai scrivendo codice che verrà importato e utilizzato da altri, non presumere che utilizzeranno direttamente il comando incorporato dict - rendendo tale presunzione rende il tuo codice più inflessibile e, in questo caso, crea bug facilmente nascosti che non rovinerebbero il programma .
Suggerisco vivamente, ai fini della correttezza, della manutenibilità e della flessibilità per i futuri utenti, di non avere mai espressioni meno flessibili e unidiomatiche nel codice quando ci sono espressioni più flessibili e idiomatiche.
is
è un test per l' identità dell'oggetto . Non supporta l'ereditarietà, non supporta alcuna astrazione e non supporta l'interfaccia.
Quindi fornirò diverse opzioni che lo fanno.
Eredità di supporto:
Questa è la prima raccomandazione che vorrei fare, perché permette agli utenti di fornire le proprie sottoclasse di dict, o una OrderedDict
, defaultdict
o Counter
dal modulo collezioni:
if isinstance(any_object, dict):
Ma ci sono opzioni ancora più flessibili.
Astrazioni di supporto:
from collections.abc import Mapping
if isinstance(any_object, Mapping):
Ciò consente all'utente del codice di utilizzare la propria implementazione personalizzata di una mappatura astratta, che include anche qualsiasi sottoclasse di dict
, e ottenere comunque il comportamento corretto.
Usa l'interfaccia
Di solito ascolti il consiglio OOP, "programma su un'interfaccia".
Questa strategia sfrutta il polimorfismo o la tipizzazione delle anatre di Python.
Quindi prova ad accedere all'interfaccia, rilevando gli errori previsti specifici ( AttributeError
nel caso non ce ne sia .items
e TypeError
nel caso items
non sia richiamabile) con un ragionevole fallback - e ora qualsiasi classe che implementa quell'interfaccia ti darà i suoi elementi (la nota .iteritems()
è andata in Python 3):
try:
items = any_object.items()
except (AttributeError, TypeError):
non_items_behavior(any_object)
else: # no exception raised
for item in items: ...
Forse potresti pensare che usare la tipizzazione anatra in questo modo esca troppo nel consentire troppi falsi positivi, e potrebbe essere, a seconda dei tuoi obiettivi per questo codice.
Conclusione
Non utilizzare is
per controllare i tipi per il flusso di controllo standard. Usa isinstance
, considera le astrazioni come Mapping
o MutableMapping
e considera di evitare del tutto il controllo del tipo, usando direttamente l'interfaccia.