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ć dictjako 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.
isjest 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, defaultdictalbo Counterz 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ę dicti 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 ( AttributeErrorw przypadku, gdy nie ma, .itemsa TypeErrorjeśli itemsnie 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 isdo sprawdzania typów dla standardowego przepływu sterowania. Użyj isinstance, rozważ abstrakcje takie jak Mappinglub MutableMappingi całkowicie unikaj sprawdzania typu, używając bezpośrednio interfejsu.