Jak sprawdziłbyś, czy zmienna jest słownikiem w Pythonie?
To jest doskonałe pytanie, ale jest to niefortunne, że większość upvoted prowadzi odpowiedź z ubogiej rekomendacji type(obj) is dict
.
(Należy pamiętać, że nie należy również używać dict
jako nazwy zmiennej - jest to nazwa wbudowanego obiektu).
Jeśli piszesz kod, który zostanie zaimportowany i użyty przez innych, nie zakładaj, że będą oni korzystać bezpośrednio z wbudowanego dict - dzięki temu domniemaniu twój kod jest bardziej nieelastyczny iw tym przypadku twórz łatwo ukryte błędy, które nie spowodowałyby błędu programu .
Zdecydowanie sugeruję, dla celów poprawności, łatwości konserwacji i elastyczności dla przyszłych użytkowników, aby nigdy nie mieli mniej elastycznych, jednoznacznych wyrażeń w kodzie, gdy są bardziej elastyczne, idiomatyczne wyrażenia.
is
jest testem tożsamości obiektu . Nie obsługuje dziedziczenia, nie obsługuje żadnej abstrakcji i nie obsługuje interfejsu.
Podam więc kilka opcji, które to robią.
Wspieranie dziedziczenia:
Jest to pierwsza rekomendacja chciałbym zrobić, ponieważ pozwala użytkownikom dostarczać własne podklasy dict, albo ich OrderedDict
, defaultdict
albo Counter
z modułu zbiory:
if isinstance(any_object, dict):
Ale są jeszcze bardziej elastyczne opcje.
Obsługiwane abstrakcje:
from collections.abc import Mapping
if isinstance(any_object, Mapping):
Dzięki temu użytkownik Twojego kodu może użyć własnej niestandardowej implementacji abstrakcyjnego odwzorowania, która obejmuje również dowolną podklasę dict
i nadal uzyskać prawidłowe zachowanie.
Użyj interfejsu
Często słyszysz poradę OOP „program do interfejsu”.
Ta strategia wykorzystuje polimorfizm lub pisanie kaczek w Pythonie.
Więc po prostu spróbuj uzyskać dostęp do interfejsu, wychwytując określone oczekiwane błędy ( AttributeError
w przypadku, gdy nie ma, .items
a TypeError
jeśli items
nie można wywołać) z rozsądną rezerwą - a teraz każda klasa, która implementuje ten interfejs, da ci swoje elementy (uwaga .iteritems()
zniknęła w Pythonie 3):
try:
items = any_object.items()
except (AttributeError, TypeError):
non_items_behavior(any_object)
else: # no exception raised
for item in items: ...
Być może pomyślisz, że takie pisanie kaczy posuwa się zbyt daleko, by pozwolić na zbyt wiele fałszywych trafień, i może być tak, w zależności od celów tego kodu.
Wniosek
Nie używaj is
do sprawdzania typów dla standardowego przepływu sterowania. Użyj isinstance
, rozważ abstrakcje takie jak Mapping
lub MutableMapping
i całkowicie unikaj sprawdzania typu, używając bezpośrednio interfejsu.