Wie überprüfe ich, ob eine Variable ein Wörterbuch in Python ist?

214

Wie würden Sie überprüfen, ob eine Variable ein Wörterbuch in Python ist?

Ich möchte beispielsweise, dass die Werte im Wörterbuch durchlaufen werden, bis ein Wörterbuch gefunden wird. Führen Sie dann eine Schleife durch die gefundene:

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)
Riley
quelle
Auch stackoverflow.com/questions/378927/… (das als Duplikat des oben genannten markiert ist).
NPE
40
Nein, das ist nicht die gleiche Frage. Die Antworten auf diese und die anderen hier aufgeführten Fragen enthalten im Wesentlichen dieselben Informationen. Die Antwort auf "So überprüfen Sie, ob eine Variable ein Wörterbuch in Python ist" lautet "Use type () oder isinstance ()", was dann zu einer neuen Frage führt, was der Unterschied zwischen type () und isinstance () ist. . Aber die Person, die die erste Frage stellt, kann das unmöglich wissen, bis die erste Frage beantwortet ist. Ergo, verschiedene Fragen, die wichtig sind, wenn Sie auf der Website nach Ihrer Frage suchen.
13
Ich stimme @mbakeranalecta zu. Ich bin hierher gekommen, um die Antwort auf die Frage "Wie wird überprüft, ob eine Variable ein Wörterbuch in Python ist?" Zu suchen. und ich hätte nie gedacht, meine Antwort in "Unterschiede zwischen isinstance () und type () in Python" zu suchen.
Lodebari
5
Um zu überprüfen, ob eine Variable insbesondere ein Wörterbuch ist, sollten Sie wahrscheinlich verwenden isinstance(v, collections.abc.Mapping). Mit anderen Worten, dies ist kein genaues Duplikat von "Unterschiede zwischen isinstance () und type ()".
Josh Kelley

Antworten:

279

Sie könnten verwenden if type(ele) is dictoder verwenden, isinstance(ele, dict)was funktionieren würde, wenn Sie eine Unterklasse hätten dict:

d = {'abc':'abc','def':{'ghi':'ghi','jkl':'jkl'}}
for ele in d.values():
    if isinstance(ele,dict):
       for k, v in ele.items():
           print(k,' ',v)
Padraic Cunningham
quelle
70
Ich habe diese Antwort abgelehnt, weil die richtige Antwort auf die allgemeine Frage lautet : isinstance(ele, collections.Mapping). Es funktioniert für dict(), collections.OrderedDict()und collections.UserDict(). Das Beispiel in der Frage ist spezifisch genug, damit Padriacs Antwort funktioniert, aber es ist nicht gut genug für den allgemeinen Fall.
Alexander Ryzhov
3
Ich habe diese Antwort abgelehnt, denn wenn Sie aufrufen wollen, ele.items()warum überprüfen Sie den Typ? EAFP / Ente-Eingabe funktioniert hier, wickeln nur for k,v in ele.items()in try...except (AttributeError, TypeError). Wenn eine Ausnahme eleitems
ausgelöst
@Padraic Cunningham Ihr hypothetischer Randfall würde erfordern, dass Ihre benutzerdefinierte Klasse "100% kein Diktat" 1. eine items()Methode 2. hatte, die zufällig eine iterable ergab, und 3. wobei jedes Element dieser iterable als 2 dargestellt werden kann -Tupel. Zu diesem Zeitpunkt hat Ihr benutzerdefiniertes Objekt bereits ein halbes Diktat implementiert. Für die Zwecke des aufgelisteten Codes haben wir uns nur um die bedingte Erweiterung des verschachtelten Elements gekümmert, und Ihr benutzerdefiniertes Objekt implementiert dies bereits. (Es ist ein bisschen ironisch, dass Sie @Alexander Ryzhovs Kommentar als zu allgemein kritisieren, aber jetzt einen allgemeinen Fall
ansprechen
1
@PadraicCunningham Ich würde lieber nicht Leuten beibringen, die mit Python-Anti-Mustern nicht allzu vertraut sind. Es gibt nur sehr wenige Anwendungsfälle in Python, die eine explizite Typüberprüfung erfordern - die meisten stammen aus dem Erben einer schlechten Implementierung ('Gottobjekte', Überschreiben von Standardbibliotheks- / Sprachkonstrukten usw.). Die ursprüngliche Frage ist selbst ein XY-Problem. Warum muss das OP den Typ überprüfen? Denn gemäß ihrem Code möchten sie wirklich überprüfen, ob sich ein Element in ihrer Sammlung wie eine Sammlung verhält (Implementierungen items(), die eine verschachtelte Iterierbarkeit ergeben).
Cowbert
4
@AlexanderRyzhov Warum nicht diesen Ansatz als Antwort posten? BTW als Josh Kelley oben kommentierte was darauf hindeutet collections.abc.Mapping, könnte ein Hinweis angebracht sein , dass sie das gleiche sind, aber collections.abcnicht verfügbar ist, bevor Python 3.3. collections.MappingAlias ​​ist in Python 3.6 noch verfügbar, aber nicht dokumentiert, daher sollte man es wahrscheinlich vorziehen collections.abc.Maping.
Yushin Washio
3

Das OP hat die Startvariable nicht ausgeschlossen. Der Vollständigkeit halber wird hier der allgemeine Fall der Verarbeitung eines vermeintlichen Wörterbuchs behandelt, das Elemente als Wörterbücher enthalten kann.

Befolgen Sie auch die von Python (3.8) empfohlene Methode zum Testen des Wörterbuchs in den obigen Kommentaren.

from collections.abc import Mapping

dict = {'abc': 'abc', 'def': {'ghi': 'ghi', 'jkl': 'jkl'}}

def parse_dict(in_dict): 
    if isinstance(in_dict, Mapping):
        for k, v in in_dict.items():
            if isinstance(v, Mapping):
                for k, v in v.items():
                    print(k, v)
            else:
                print(k, v)

parse_dict(dict)
CodeMantle
quelle
dict.iteritems()existiert nicht in Python 3, sollten Sie dict.items()stattdessen verwenden.
Arkelis
@Arkelis Ups, habe diesen Teil gerade kopiert / eingefügt, danke für den Hinweis - jetzt korrigiert.
CodeMantle
3

Wie würden Sie überprüfen, ob eine Variable ein Wörterbuch in Python ist?

Dies ist eine ausgezeichnete Frage, aber es ist bedauerlich, dass die am besten bewertete Antwort mit einer schlechten Empfehlung führt type(obj) is dict.

(Beachten Sie, dass Sie auch keinen dictVariablennamen verwenden sollten - es ist der Name des eingebauten Objekts.)

Wenn Sie Code schreiben, der von anderen importiert und verwendet wird, gehen Sie nicht davon aus, dass sie das eingebaute Diktat direkt verwenden. Diese Annahme macht Ihren Code unflexibler und in diesem Fall leicht versteckte Fehler, die das Programm nicht fehlerhaft machen würden .

Ich empfehle dringend, aus Gründen der Korrektheit, Wartbarkeit und Flexibilität für zukünftige Benutzer niemals weniger flexible, unidiomatische Ausdrücke in Ihrem Code zu haben, wenn es flexiblere, idiomatische Ausdrücke gibt.

isist ein Test für die Objektidentität . Es unterstützt keine Vererbung, keine Abstraktion und keine Schnittstelle.

Daher werde ich verschiedene Optionen bereitstellen, die dies tun.

Unterstützende Vererbung:

Dies ist die erste Empfehlung , die ich machen würde, denn es ermöglicht es Benutzern , ihre eigene Unterklasse von dict zu versorgen, oder eine OrderedDict, defaultdictoder Counteraus den Sammlungen Modul:

if isinstance(any_object, dict):

Es gibt aber noch flexiblere Möglichkeiten.

Unterstützende Abstraktionen:

from collections.abc import Mapping

if isinstance(any_object, Mapping):

Auf diese Weise kann der Benutzer Ihres Codes eine eigene benutzerdefinierte Implementierung einer abstrakten Zuordnung verwenden, die auch eine Unterklasse von enthält dict, und dennoch das richtige Verhalten erhalten.

Verwenden Sie die Schnittstelle

Sie hören häufig den OOP-Rat "Programmieren auf eine Schnittstelle".

Diese Strategie nutzt Pythons Polymorphismus oder Ententypisierung.

Versuchen Sie also einfach, auf die Schnittstelle zuzugreifen und die spezifischen erwarteten Fehler ( AttributeErrorfalls es keine gibt .itemsund TypeErrorfalls sie itemsnicht aufrufbar sind) mit einem vernünftigen Fallback abzufangen - und jetzt gibt Ihnen jede Klasse, die diese Schnittstelle implementiert, ihre Elemente (Anmerkung .iteritems()ist in Python weg) 3):

try:
    items = any_object.items()
except (AttributeError, TypeError):
    non_items_behavior(any_object)
else: # no exception raised
    for item in items: ...

Vielleicht denken Sie, dass die Verwendung von Enten-Typisierung zu weit geht, um zu viele Fehlalarme zuzulassen, und dies kann abhängig von Ihren Zielen für diesen Code der Fall sein.

Fazit

Nicht verwenden is, um Typen auf Standardkontrollfluss zu überprüfen. Verwenden Sie isinstance, berücksichtigen Sie Abstraktionen wie Mappingoder MutableMappingund vermeiden Sie die Typprüfung insgesamt, indem Sie die Schnittstelle direkt verwenden.

Aaron Hall
quelle