Jak sprawdziłbyś, czy zmienna jest słownikiem w Pythonie?
Na przykład chciałbym, aby przeglądał wartości w słowniku, dopóki nie znajdzie słownika. Następnie przejdź przez ten, który znajdzie:
dict = {'abc': 'abc', 'def': {'ghi': 'ghi', 'jkl': 'jkl'}}
for k, v in dict.iteritems():
if ###check if v is a dictionary:
for k, v in v.iteritems():
print(k, ' ', v)
else:
print(k, ' ', v)
python
dictionary
Riley
źródło
źródło
isinstance(v, collections.abc.Mapping)
. Innymi słowy, nie jest to dokładna kopia „Różnic między isinstance () a type ()”.Odpowiedzi:
Możesz użyć
if type(ele) is dict
lub użyć,isinstance(ele, dict)
który działałby, gdybyś podklasowałdict
:źródło
isinstance(ele, collections.Mapping)
. To działa nadict()
,collections.OrderedDict()
, icollections.UserDict()
. Przykład w pytaniu jest wystarczająco konkretny, aby odpowiedź Padriaca zadziałała, ale nie jest wystarczająca w przypadku ogólnym.ele.items()
dlaczego sprawdzasz typ? EAFP / kaczego wpisując działa, po prostu zawinąćfor k,v in ele.items()
wtry...except (AttributeError, TypeError)
. Jeśli powstanie wyjątek, wieszele
,items
że nie ma takiego, który dajeitems()
metodę 2. która właśnie tak się wydarzyła, umożliwiając iterację i 3. gdzie każdy element tej iteracji może być reprezentowany jako 2 -tuple. W tym momencie Twój obiekt niestandardowy już zaimplementował już połowę nagrania. Dla celów wymienionego kodu dbaliśmy tylko o warunkowe rozwinięcie zagnieżdżonego elementu, a Twój obiekt niestandardowy już to implementuje. (Trochę ironiczne jest to, że krytykujesz komentarz Aleksandra Ryżowa za to, że jest zbyt ogólny, ale terazitems()
które dają zagnieżdżoną iterowalność).collections.abc.Mapping
, uwaga może być odpowiednia, że są takie same, alecollections.abc
nie jest dostępna przed Pythonem 3.3.collections.Mapping
alias jest nadal dostępny w Pythonie 3.6, ale nie jest udokumentowany, więc prawdopodobnie należy go preferowaćcollections.abc.Maping
.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
alboCounter
z modułu zbiory:if isinstance(any_object, dict):
Ale są jeszcze bardziej elastyczne opcje.
Obsługiwane abstrakcje:
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
aTypeError
jeśliitems
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):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żyjisinstance
, rozważ abstrakcje takie jakMapping
lubMutableMapping
i całkowicie unikaj sprawdzania typu, używając bezpośrednio interfejsu.źródło
OP nie wykluczył zmiennej początkowej, więc dla kompletności tutaj jest, jak poradzić sobie z ogólnym przypadkiem przetwarzania domniemanego słownika, który może zawierać elementy jako słowniki.
Również postępując zgodnie z zalecanym przez Pythona (3.8) sposobem testowania słownika w powyższych komentarzach.
źródło
dict.iteritems()
nie istnieje w Pythonie 3, powinieneś użyćdict.items()
zamiast tego.